【问题标题】:How can I build an index and a boolean query in elastic search that performs prefix matching on some fields and exact phrase matching on other fields?如何在弹性搜索中构建索引和布尔查询,对某些字段执行前缀匹配,对其他字段执行精确短语匹配?
【发布时间】:2020-06-25 04:27:18
【问题描述】:

我想创建一个包含名为“home_city”的字段的索引。 我将需要在这个索引上执行搜索,返回所有带有 home_city 字段的文档,该字段正好是“Little Rock”。 我还需要对该索引执行搜索,该索引返回所有带有 home_city 字段的文档,该字段包含以查询字符串为前缀的任何单词。例如,如果查询字符串是“Ne”,那么 home_city = “New York” 或 home_city = “Long Neck” 或 home_city = “Nevinton” 的文档将出现在结果中。

我可以创建一个允许这两个查询之一的索引,但不能同时允许。

例如,如果我指示索引使用 Elastic 的“关键字”分析器,前一个搜索(确切的完整关键字搜索)就可以工作。我在创建这样的索引时指定了这一点...

PUT my_index
{
   "mappings":{
       "properties":{
          "home_city": {
             "type":"text",
             "analyzer":"keyword", 
         }
      }
   }
}

以下查询正确返回所有带有 home_city = "Little Rock" 字段的文档

{
  "query": {
    "bool": {
      "must": [
        {
              "query_string":{
                 "query":"Little Rock" 
           }
        }]
     }
   }
}

此外,正如预期的那样,如果查询不完全是“Little Rock”,而是“Little”或“Rock”,则响应不包括 home_city="Little Rock" 的文档。很好,这就是我们想要的。

如果我使用默认设置创建索引,则后一种(前缀匹配)搜索有效。 查询看起来像这样...

{
  "query": {
            "match": {
                "home_city": "Di"
            }
      }
}

返回字段 home_city = "San Diego" 的文档和字段 home_city = "Diamondville" 的文档。

但是,我无法让这两个查询在同一个索引上工作。如果我在创建索引时指定关键字分析器,并执行第二个查询(前缀匹配查询),则没有文档匹配。

如何创建一个索引帽子,它将与查找与整个查询字符串完全匹配的文档的查询以及查找包含该查询作为前缀的文档的查询一起使用。

最终,我们有兴趣将前缀匹配替换为更复杂的匹配,包括前缀匹配以及其他技术。但是现在,我们只想弄清楚上面描述的问题。

干杯。

【问题讨论】:

标签: elasticsearch indexing lucene tokenize prefix


【解决方案1】:

您可以使用fields进行映射

映射

{
   "mappings":{
       "properties":{
          "home_city": {
             "type":"text",      --> will store as tokens using standard analyzer
             "fields": {
               "keyword":{
                 "type":"keyword" --> will store entire text as single token
               }
             }
         }
      }
   }
}

查询 1:

GET index_10/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "query_string": {
            "query": "Little Rock"
          }
        }
      ]
    }
  }
}

查询 2: 使用 match_phrase_prefix 而不是 match_phrase

匹配词组 1.所有条款必须出现 2.他们必须有相同的顺序

Match_phrase_prefix

以与提供的相同顺序返回包含所提供文本的单词的文档。所提供文本的最后一个词被视为前缀,匹配以该词开头的任何单词。

GET index_10/_search
{
  "query": {
    "match_phrase_prefix": {
      "home_city": "di"
    }
  }
}

需要考虑的要点

  1. 如果用户输入,最好使用 simple_query_string 而不是 query_string,因为它不会在搜索语法错误的情况下引发错误。
  2. Match_phrase_prefix 只会在标记的开头进行搜索。如果需要在文本中的任何位置进行搜索,您可以探索 NGrams、EdgeNgrams 以及内置的自动完成和 search_as_you_type。

【讨论】:

  • 第一个查询不是我们需要的。即使查询字符串是“Little”或“Rock”,它也会返回带有 home_city = Little Rock 的文档。这是不正确的。仅当查询字符串为“Little Rock”时,我们才应返回带有 home_city = Little Rock 的文档。
  • 我需要将相同的字段存储为文本以及单个标记,因为有时我会对字段中的任何单词进行前缀搜索,而其他时候我会在整个字段。
  • 这适用于第一个查询。只有对“Little Rock”的精确查询才会返回带有 home_city="Little Rock...{ "query": { "bool": { "must": [ { "query_string": { "fields": ["home_city.关键字"], "查询": "叶河" } } ] } } }
  • 您也可以在 home_city.keyword 上使用术语查询来进行精确匹配。您的问题是否已解决或有待解决?
  • 使用字段可以以不同的方式存储相同的字段。字段 home_city 存储为文本(以标记分隔)并且 home_city.keyword 是非分析的,即字符串存储为单个标记。所以 home_city.keyword 可以用于精确匹配, home_city 用于令牌匹配
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-11
  • 2021-10-19
  • 2011-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多