首页 > 解决方案 > 如何在所有字段中进行搜索并使用弹性搜索中指定的字段进行搜索?

问题描述

我对弹性搜索很陌生,我如何编写一个查询,在文档的所有字段中搜索关键字(即测试关键字),以及在特定字段中搜索的另一个关键字。

这可以使用query_string但我们不能在指定嵌套字段的嵌套字段中进行搜索,所以我使用LUQUM将 lucene 查询转换为 Elasticsearch DSL。

以下是示例用例:

我有一个映射:

"mappings": {
    "properties": {
      "grocery_name":{
        "type": "text"
       },
      "items": {
        "type": "nested",
        "properties": {
          "name": {
            "type": "text"
          },
          "stock": {
            "type": "integer"
          },
          "category": {
            "type": "text"
          }
        }
      }
    }
  }
}

数据如下所示

{
  "grocery_name": "Elastic Eats",
  "items": [
    {
      "name": "Red banana",
      "stock": "12",
      "category": "fruit"
    },
    {
      "name": "Cavendish banana",
      "stock": "10",
      "category": "fruit"
    },
    {
      "name": "peach",
      "stock": "10",
      "category": "fruit"
    },
    {
      "name": "carrot",
      "stock": "9",
      "category": "vegetable"
    },
    {
      "name": "broccoli",
      "stock": "5",
      "category": "vegetable"
    }
  ]
}

我如何查询以获取所有项目名称与来自grocery_name: Elastic Eats的香蕉相匹配的项目?

尝试使用*and _all,它没有用。

示例查询:

{
   "query": {
        "bool": {
            "must": [
                {
                    "match_phrase": {
                        "grocery_name": {
                            "query": "Elastic Eats"
                        }
                    }
                },
                {
                    "match": {
                        "*": {
                            "query": "banana",
                            "zero_terms_query": "all"
                        }
                    }
                }
            ]
        }
    }
}

我确定我遗漏了一些明显的东西,但是我已经阅读了手册,但我一点也不高兴。

更新:启用include_in_parent嵌套对象适用于以下查询,但它会在内部复制肯定会影响内存的数据。

{
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "grocery_name": {
              "query": "Elastic Eats"
            }
          }
        },
        {
          "multi_match": {
              "query": "banana"
          }
        }
      ]
    }
  }
}

有没有其他方法可以做到这一点?

标签: elasticsearchluceneelasticsearch-dslelasticsearch-dsl-py

解决方案


您需要使用带有 inner_hits 的嵌套匹配查询,从而导致内部嵌套查询自动匹配相关的嵌套级别,而不是根

搜索查询

 {
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "grocery_name": "elastic"
          }
        },
        {
          "nested": {
            "path": "items",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "items.name": "banana"
                    }
                  }
                ]
              }
            },
            "inner_hits": {}
          }
        }
      ]
    }
  }
}

搜索结果:

 "inner_hits": {
          "items": {
            "hits": {
              "total": {
                "value": 2,
                "relation": "eq"
              },
              "max_score": 0.744874,
              "hits": [
                {
                  "_index": "stof_64273970",
                  "_type": "_doc",
                  "_id": "1",
                  "_nested": {
                    "field": "items",
                    "offset": 0
                  },
                  "_score": 0.744874,
                  "_source": {
                    "name": "Red banana",
                    "stock": "12",
                    "category": "fruit"
                  }
                },
                {
                  "_index": "stof_64273970",
                  "_type": "_doc",
                  "_id": "1",
                  "_nested": {
                    "field": "items",
                    "offset": 1
                  },
                  "_score": 0.744874,
                  "_source": {
                    "name": "Cavendish banana",
                    "stock": "10",
                    "category": "fruit"
                  }
                }
              ]
            }

更新1:

根据您的评论,您可以针对您的用例使用多重匹配查询

如果未提供任何字段,则 multi_match 查询默认为 index.query.default_field 索引设置,而后者又默认为 *。

(*) 提取映射中符合术语查询条件的所有字段并过滤元数据字段。然后组合所有提取的字段以构建查询。

搜索查询:

    {
      "query": {
        "bool": {
          "filter": [
            {
              "term": {
                "grocery_name": "elastic"
              }
            },
            {
              "nested": {
                "path": "items",
                "query": {
                  "bool": {
                    "must": [
                      {
                        "multi_match": {
                          "query": "banana"    <-- note this
                        }
                      }
                    ]
                  }
                },
                "inner_hits": {}
              }
            }
          ]
        }
      }
    }

更新 2:

您需要使用多个 bool 查询的组合,如下所示:

{
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "grocery_name": {
              "query": "Elastic Eats"
            }
          }
        },
        {
          "bool": {
            "should": [
              {
                "bool": {
                  "must": [
                    {
                      "multi_match": {
                        "query": "banana"
                      }
                    }
                  ]
                }
              },
              {
                "bool": {
                  "must": [
                    {
                      "nested": {
                        "path": "items",
                        "query": {
                          "bool": {
                            "must": [
                              {
                                "multi_match": {
                                  "query": "banana"
                                }
                              }
                            ]
                          }
                        },
                        "inner_hits": {}
                      }
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  }
}

推荐阅读