首页 > 解决方案 > 如果查询在引号之间,如何从弹性搜索中获取精确的文本匹配

问题描述

我使用 php 为二进制文档(fscrawler)实现了弹性搜索。它在默认设置下工作得很好。我可以在文档中搜索我想要的单词,并且得到不区分大小写的结果。但是,我现在想做完全匹配,即在当前搜索的顶部,如果查询用引号括起来,我想得到只与查询完全匹配的结果.. 甚至区分大小写。

我的映射如下所示:

"settings": {
"number_of_shards": 1,
"index.mapping.total_fields.limit": 2000,
"analysis": {
  "analyzer": {
    "fscrawler_path": {
      "tokenizer": "fscrawler_path"
    }
  },
  "tokenizer": {
    "fscrawler_path": {
      "type": "path_hierarchy"
    }
  }
}
.
.
.
  "content": {
    "type": "text",
    "index": true
  },

我对文档的查询如下所示:

    if ($q2 == '') {
    $params = [
        'index' => 'trial2',
        'body' => [
            'query' => [
                'match_phrase' => [
                        'content' => $q
                ]
            ]
        ]
    ];

    $query = $client->search($params);
    $data['q'] = $q;
}

对于完全匹配(不起作用):

    if ($q2 == '') {
        $params = [
            'index' => 'trial2',
            'body' => [
                'query' => [
                    'filter' =>[
                        'term' => [
                            'content' => $q
                        ]
                    ]
                ]
            ]
        ];

        $query = $client->search($params);
        $data['q'] = $q;
    }

content 字段是文档的主体。如何实现内容字段中特定单词或短语的完全匹配?

标签: phpelasticsearch

解决方案


据我所知,您的content领域会非常大,因为许多文档可能超过 2-3 MB,而且字数很多。

keyword根据您之前提到的问题的答案,使用字段进行完全匹配是没有意义的keyword仅当您的数据是结构化的时,您才应该使用keyword数据类型进行精确匹配

我的理解是content你拥有的领域是非结构化的。在这种情况下,您可能希望在您的领域中使用Whitespace Analyzer 。content

此外,对于完全匹配的短语,您可以查看Match Phrase查询。

以下是足以满足您的用例的示例索引、文档和查询。

映射:

PUT mycontent_index
{
  "mappings": {
    "properties": {
      "content":{
        "type":"text",
        "analyzer": "whitespace"            <----- Note this
      }
    }
  }
}

样本文件:

POST mycontent_index/_doc/1
{
  "content": """
      There is no pain you are receding
      A distant ship smoke on the horizon
      You are only coming through in waves
      Your lips move but I can't hear what you're saying
  """
}

POST mycontent_index/_doc/2
{
  "content": """          
      there is no pain you are receding
      a distant ship smoke on the horizon
      you are only coming through in waves
      your lips move but I can't hear what you're saying
  """
}

短语匹配:(按顺序搜索单词)

POST mycontent_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {                   <---- Note this for phrase match
            "content": "There is no pain"
          }
        }
      ]
    }
  }
}

匹配查询:

POST mycontent_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {                          <---- Use this for token based search
            "content": "there"
          }
        }
      ]
    }
  }
}

请注意,您的回应应该是相应的。

对于单词的精确匹配,只需使用简单的匹配查询。

请注意,当您不指定任何分析器时,ES 默认使用标准分析器,这将导致所有标记在存储到倒排索引之前转换为小写。但是,空白分析器 不会将标记转换为小写。结果Therethere在您的 ES 索引中存储为两个不同的标记。

我假设您了解分析分析器的概念,如果没有,我建议您浏览链接,因为这将帮助您更多地了解我在说什么。

更新答案:

了解您的要求后,您无法在单个字段上应用多个分析器,因此基本上您有两个选择:

选项 1:使用多个索引

选项 2:在映射中使用多字段,如下所示:

这样,您的脚本或服务层将具有根据您的输入值推送到不同索引或字段的逻辑(具有双引号的和简单标记的)

多场映射:

PUT <your_index_name>
{ 
   "mappings":{ 
      "properties":{ 
         "content":{ 
            "type":"text",                     <--- Field with standard analyzer
            "fields":{ 
               "whitespace":{ 
                  "type":"text",               <--- Field with whitespace
                  "analyzer":"whitespace"       
               }
            }
         }
      }
   }
}

理想情况下,我希望使用第一个解决方案,即使用具有不同映射的多个索引,但是我强烈建议您重新审视您的用例,因为它在管理这样的查询时没有意义,但又是您的电话。

注意: 单节点集群是您可以做的最糟糕的选择,特别是不适用于生产。

我建议您在单独的问题中提出详细说明您的文档数量、未来 5 年的增长率或其他内容的问题,您的用例会更加阅读繁重还是编写密集?这个集群是其他团队也可能想要利用的东西吗?我建议您阅读更多内容并与您的团队或经理讨论,以更清楚地了解您的情况。

希望这可以帮助。


推荐阅读