Elasticsearch如何匹配字段标记为查询标记的子集的文档

时间:2016-01-29 10:32:41

标签: elasticsearch querydsl

我有一个关键字/关键短语字段我使用标准分析器进行标记。如果有一个搜索短语包含该字段的所有标记,我希望此字段匹配。

例如,如果字段值为" veni,vidi,vici"搜索短语是" Ceaser veni,vidi,vici"我希望这个搜索短语匹配,但搜索短语" veni,vidi"不匹配。

我还需要" vidi,veni,vici" (奇怪!)匹配。所以这些术语的位置和顺序并不重要。我认为短语匹配对我来说不太有用。

我可以使用" bool查询"使用" minimum_should_match"这个特定示例的参数,但实际上并不是我想要的最小值应匹配的是搜索短语中令牌的比率/数量。

2 个答案:

答案 0 :(得分:2)

Pure ES解决方案就是这样的。您将需要两个请求。

1)首先,您需要通过analyze api传递用户查询以获取所有搜索令牌。

curl -XGET 'localhost:9200/_analyze' -d '
{
  "analyzer" : "standard",
  "text" : "Ceaser veni,vidi,vici"
}'

您将获得4个令牌 ceaser veni vidi vici 。您需要将这些标记作为数组传递给下一个search请求。

2)我们需要搜索代币为子集搜索令牌的文档。

{
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "must": [
            {
              "query": {
                "match": {
                  "title": "Ceaser veni,vidi,vici"
                }
              }
            },
            {
              "script": {
                "script": "if(search_tokens.containsAll(doc['title'].values)){return true;}",
                "params": {
                  "search_tokens": [
                    "ceaser",
                    "veni",
                    "vidi",
                    "vici"
                  ]
                }
              }
            }
          ]
        }
      }
    }
  }
}

此处过滤器中第一个match query的作业是缩小应运行脚本的文档的范围。 containsAll方法将检查文档令牌是否为sublist搜索令牌。这将是缓慢的,但将使用您当前的设置完成工作。您可以做的一个重大改进是将标记存储为数组,以便可以用该字段替换doc['title'].values,这将改进脚本。

希望这有帮助!

答案 1 :(得分:0)

没有内置解决方案,但这有效:

  1. 在每个文档的字段中添加一个包含术语数的额外字段。所以在你的" veni,vidi,vici"例如,您将拥有类似" field_term_count"的字段。 :3。

  2. 对搜索查询中的每个标记执行单独匹配搜索。

  3. 将每个文档匹配的搜索次数与至少一个匹配项相加(例如,带有文档ID键和计数值的哈希表)。

  4. 将3中的匹配数与" field_term_count"进行比较每个匹配文档的字段。如果它们相等则文档就是匹配。

  5. 然后" Ceaser veni,vidi,vici"将匹配搜索短语" veni,vidi"不会,如所希望的那样。对于合理数量的匹配,它应该非常快。