使用 lucene 模糊运算符时,Elasticsearch 查询和过滤器会给出不同的文档计数

标签 elasticsearch lucene

使用 ElasticSearch v1.7.2 和相当大的索引,我得到了以下两个搜索的不同文档计数,它们在 query_string 中使用模糊搜索。

查询:

{
  "query": {
     "query_string": {
        "query": "rapt~4"
     }
  }
}

过滤器:

{
 "filter": {
    "query": {
       "query_string": {
          "query": "rapt~4"
       }
    }
 }
}

过滤器给出的结果比查询大约 5%。为什么文档计数会不同?是否有我可以指定的选项来使它们保持一致?

请注意,这种不一致只会在我使用中等大小的数据集时发生。我已尝试将几个 (<10) 个匹配过滤器但不匹配查询的文档插入到一个干净的集群中,之后我的查询和过滤器都成功地确实匹配了所有文档。但是,在单个索引、单个类型和数百个文档的集群中,我开始看到差异。

使用 explain=true 选项,query 分数似乎是使用 Practical Scoring Function 计算的.该解释提供了有关提升、queryNorm、idf 和术语权重的信息。相比之下,filter 解释仅报告 Practical Scoring Function 的 boost 和 queryNorm 组件,而不是 idf 或 term weights。

下面是带有解释的回复示例。请注意,我已经从我的示例命中中删除了许多字段并简化了内容,因此除了匹配的词(在本例中为“事实”)之外,解释中的术语频率将与实际内容不匹配。这些响应是针对相同 事件的。我的问题是过滤器响应中包含了查询响应中未包含的其他匹配项。他们的解释看起来完全相同。

查询:

curl -XPOST "http://localhost:9200/index-name/example-type/_search" -H "Content-Type: application/json" -d'{"query":{"query_string":{"query":"rapt~"}},"explain":true}'

和查询响应:

{
"_source": {
  "type": "example",
  "content": "to the fact that"
},
"_explanation": {
  "value": 0.10740301,
  "description": "sum of:",
  "details": [
    {
      "value": 0.10740301,
      "description": "weight(_all:fact^0.5 in 465) [PerFieldSimilarity], result of:",
      "details": [
        {
          "value": 0.10740301,
          "description": "score(doc=465,freq=2.0), product of:",
          "details": [
            {
              "value": 0.11091774,
              "description": "queryWeight, product of:",
              "details": [
                {
                  "value": 0.5,
                  "description": "boost"
                },
                {
                  "value": 7.303468,
                  "description": "idf(docFreq=68, maxDocs=37706)"
                },
                {
                  "value": 0.03037399,
                  "description": "queryNorm"
                }
              ]
            },
            {
              "value": 0.96831226,
              "description": "fieldWeight in 465, product of:",
              "details": [
                {
                  "value": 1.4142135,
                  "description": "tf(freq=2.0), with freq of:",
                  "details": [
                    {
                      "value": 2,
                      "description": "termFreq=2.0"
                    }
                  ]
                },
                {
                  "value": 7.303468,
                  "description": "idf(docFreq=68, maxDocs=37706)"
                },
                {
                  "value": 0.09375,
                  "description": "fieldNorm(doc=465)"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
}

过滤器:

curl -XPOST "http://localhost:9200/index-name/example-type/_search" -H "Content-Type: application/json" -d'{"query":{"filtered":{"filter":{"fquery":{"query":{"query_string":{"query":"rapt~"}}}}}},"explain":true}'

并过滤响应:

{
"_source": {
  "type": "example",
  "content": "to the fact that"
},
"_explanation": {
  "value": 1,
  "description": "ConstantScore(cache(+_type:example-type +org.elasticsearch.index.search.nested.NonNestedDocsFilter@737a6633)), product of:",
  "details": [
    {
      "value": 1,
      "description": "boost"
    },
    {
      "value": 1,
      "description": "queryNorm"
    }
  ]
}
}

当我将过滤器包装在一个常量分数查询中时,我得到了与过滤器完全相同的一组结果(同样,多于查询),但解释看起来更清晰:

恒定分数查询包装过滤器:

curl -XPOST "http://localhost:9200/index-name/example-type/_search" -H "Content-Type: application/json" -d'{"query":{"constant_score":{"filter":{"query":{"query_string":{"query":"rapt~"}}}}},"explain":true}'

和常量分数查询包装过滤器响应:

{
"_source": {
  "type": "example",
  "content": "to the fact that"
},
"_explanation": {
  "value": 1,
  "description": "ConstantScore(QueryWrapperFilter(_all:rapt~2)), product of:",
  "details": [
    {
      "value": 1,
      "description": "boost"
    },
    {
      "value": 1,
      "description": "queryNorm"
    }
  ]
}
}

因为过滤器返回的结果比查询更多,我的猜测是实用评分函数最终对与查询匹配的文档评分为 0。但是,对于“匹配"查询,评分函数的任何组成部分都不应为零。

编辑:我在一个由 238 个文档组成的小集群上重新创建了这个问题(请注意,文档的内容是从在维基百科文本上训练的 ngram 语言模型生成的。)。我已经发布了 clusterjson events在保管箱上。要查看此数据的问题,请运行以下查询,它返回 id=138 的事件:

{
 "explain": true,
 "query": {
    "bool": {
       "must_not": [
          {
             "query_string": {
                "query": "rap~",
                "fields": [
                   "body"
                ]
             }
          }
       ],
       "must": [
          {
             "constant_score": {
                "filter": {
                   "query": {
                      "query_string": {
                         "query": "rap~",
                         "fields": [
                            "body"
                         ]
                      }
                   }
                }
             }
          }
       ]
    }
 }
}

最佳答案

在 Elasticsearch 之前 Elasticsearch 5.x 版本中,顶层的filter 表示post_filter .后过滤器通常仅在使用聚合时才相关。

从 Elasticsearch 5.0(及更高版本)开始,您必须明确说明 post_filter 以避免这种混淆。

因此,不同之处在于您的热门查询实际上将结果限制为一组匹配文档。后过滤器有效地匹配所有内容,然后仅从命中中删除结果而不影响计数。

...it appears that the query score is computed using...

查询总是计算分数,它们旨在帮助根据项目的相关性(分数)对项目进行正确排序。过滤器从不计算分数;过滤器用于纯 bool 逻辑,不影响包含/排除之外的“相关性”。

公平地说,您可以在 Elasticsearch 1.x 中以多种方式将任何查询转换为过滤器(在 2.x 中,所有查询在正确的上下文中也是过滤器!),但我倾向于使用 fquery 。如果你这样做,那么你应该得到相同的结果:

作为查询:

{
  "query": {
     "query_string": {
        "query": "rapt~"
     }
  }
}

作为过滤器:

{
  "query": {
    "filtered": {
      "filter": {
        "fquery": {
          "query": {
            "query_string": {
              "query": "rapt~"
            }
          }
        }
      }
    }
  }
}

在 ES 2.x 中,过滤器也简化了(并且查询没有改变):

{
  "query": {
    "bool": {
      "filter": {
        "query_string": {
          "query": "rapt~"
        }
      }
    }
  }
}

关于使用 lucene 模糊运算符时,Elasticsearch 查询和过滤器会给出不同的文档计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34635815/

相关文章:

java - 在自动完成的东西中加粗用户输入

json - Elasticsearch中的SQL查询

java - org.apache.lucene.store.LockObtainFailedException : Lock obtain timed out: NativeFSLock@/var/database/schema/label/lucene/write. 锁

apache - 如何修复 java IOException : Can't find resource 'solrconfig.xml' in classpath?

elasticsearch - Grafana 条形图 : visualize sum of entries per product type for each month

c# - 如何执行SUM并在NEST中计数?

php - Elasticsearch 5.5使用CURL获取错误 'not_x_content_exception'

indexing - Apache Lucene 8.4.1 如何获取索引字段和术语列表?

elasticsearch - 计算ElasticSearch快照中的文档数

php - Elasticsearch多个术语/过滤器