【问题标题】:How to perform an exact match of field when each field is within a list in Elasticsearch当每个字段都在 Elasticsearch 的列表中时,如何执行字段的精确匹配
【发布时间】:2021-02-26 20:31:56
【问题描述】:

我的 ES 索引中存在的数据示例:

{
  "entities" : [
    {
      "fieldName" : "abc"
    },
    {
      "fieldName" : "def"
    }
  ], 
  "entities" : [
    {
      "fieldName" : "abc"
    },
    {
      "fieldName" : "def"
    }
  ],
 "entities" : [
    {
      "fieldName" : "abc"
    },
    {
      "fieldName" : "def"
    },
    {
      "fieldName" : "gh"
    }
  ]
}

我只想找到那些 fieldName 只匹配“abc”和“def”的文档,所以我尝试了 ES 的嵌套匹配查询,但问题是它也匹配除了“abc”之外还有额外字段的文档" 和 "定义"。

GET fetch_latest_version/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "entities",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "entities.fieldName": "abc"
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "nested": {
            "path": "entities",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "entities.fieldName": "def"
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }

上述查询的结果是它将列出样本数据中存在的所有 3 个文档。我只希望它只匹配第一个和第二个文档(如完全匹配),其中实体列表只有“abc”和“def”字段。我不应该匹配 fieldName 所在的第三个文档 ("abc","def","gh") 。

【问题讨论】:

    标签: python-3.x elasticsearch elasticsearch-dsl-py


    【解决方案1】:

    您可以添加must_not 查询,以删除所有具有"entities.fieldName":"gh" 的文档。如下所示修改您的搜索查询

        {
      "query": {
        "bool": {
          "must": [
            {
              "nested": {
                "path": "entities",
                "query": {
                  "bool": {
                    "must": [
                      {
                        "match": {
                          "entities.fieldName": "abc"
                        }
                      }
                    ]
                  }
                }
              }
            },
            {
              "nested": {
                "path": "entities",
                "query": {
                  "bool": {
                    "must": [
                      {
                        "match": {
                          "entities.fieldName": "def"
                        }
                      }
                    ]
                  }
                }
              }
            }
          ],
          "must_not": {
            "nested": {
              "path": "entities",
              "query": {
                "bool": {
                  "should": [
                    {
                      "match": {
                        "entities.fieldName": "gh"
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      }
    }
    

    搜索结果将是

    "hits": [
          {
            "_index": "66381155",
            "_type": "_doc",
            "_id": "1",
            "_score": 0.8266786,
            "_source": {
              "entities": [
                {
                  "fieldName": "abc"
                },
                {
                  "fieldName": "def"
                }
              ]
            }
          },
          {
            "_index": "66381155",
            "_type": "_doc",
            "_id": "2",
            "_score": 0.8266786,
            "_source": {
              "entities": [
                {
                  "fieldName": "abc"
                },
                {
                  "fieldName": "def"
                }
              ]
            }
          }
        ]
    

    更新 1:

    AFAIK 没有办法告诉 elasticsearch 确保每个文档都必须有 "fieldName":"abc" 和 "fieldName":"def"。 一种方法是在索引文档之前检查这种情况。您可以创建一个包含该值的顶级非嵌套字段。

    【讨论】:

    • 这只是一个示例,其中额外字段“gh”存在于数据中,可能存在任意数量的额外字段,其值对我来说是未知的。另外,假设一个文档只有一个字段“abc”,它也不应该匹配。只有将要指定的字段才能完全匹配。
    • @SheikhMannanSohail 请仔细阅读更新后的查询和更新的部分答案,如果这能解决您的问题,请告诉我?
    • 我检查了更新后的查询,但正如我所说,我们不能有 must_not,因为除了“gh”之外,我们不知道 fieldName 中可能存在的值。此外,可以有任意数量的额外不需要的字段名称,例如“ij”、“kl”。 update1 对我来说很不清楚。能详细点吗?
    【解决方案2】:

    我认为没有完全匹配的子查询,所以我建议创建一个以组合作为键的字段:即:“abcdef”,然后针对该字段进行精确搜索。

    如果您需要在不接触数据的情况下解决它,那么您可以使用脚本查询:

    GET /fetch_latest_version/_search
    {
      "query": {
        "bool": {
          "must": {
            "match_all": {}
          },
          "filter": {
            "bool": {
              "must": {
                "script": {
                  "script": {
                    "lang": "painless",
                    "source": "def x = doc['entities.fieldName.keyword']; x.containsAll(params.filter) && params.filter.length == x.length",
                    "params": {
                      "filter": [
                        "def",
                        "abc"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    

    我必须删除嵌套字段类型才能轻松工作

    我首先验证文档中是否存在“abc”和“def”,然后验证过滤器的长度和子过滤器是否相同。

    {
      "took" : 0,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 2,
          "relation" : "eq"
        },
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "fetch_latest_version",
            "_type" : "_doc",
            "_id" : "xf733XcBhQfuY9se1B5L",
            "_score" : 1.0,
            "_source" : {
              "entities" : [
                {
                  "fieldName" : "abc"
                },
                {
                  "fieldName" : "def"
                }
              ]
            }
          },
          {
            "_index" : "fetch_latest_version",
            "_type" : "_doc",
            "_id" : "xv743XcBhQfuY9seFR6t",
            "_score" : 1.0,
            "_source" : {
              "entities" : [
                {
                  "fieldName" : "abc"
                },
                {
                  "fieldName" : "def"
                }
              ]
            }
          }
        ]
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-02
      • 2020-11-16
      • 1970-01-01
      • 2017-11-03
      • 2014-05-11
      相关资源
      最近更新 更多