查询和过滤上下文

编辑

相关性评分

编辑

默认情况下,Elasticsearch 会根据相关性评分对匹配的搜索结果进行排序,该评分衡量每个文档与查询的匹配程度。

相关性评分是一个正浮点数,在 搜索 API 的 _score 元数据字段中返回。 _score 越高,文档的相关性就越高。虽然每种查询类型计算相关性评分的方式可能不同,但评分计算还取决于查询子句是在查询上下文中还是在过滤上下文中运行。

查询上下文

编辑

在查询上下文中,查询子句回答的问题是“此文档与此查询子句的匹配程度如何?” 除了决定文档是否匹配之外,查询子句还在 _score 元数据字段中计算相关性评分。

每当查询子句传递给 query 参数时,例如 搜索 API 中的 query 参数时,查询上下文就会生效。

过滤上下文

编辑

过滤器回答的是二元问题“此文档是否与此查询子句匹配?” 答案很简单,要么是“是”,要么是“否”。 过滤具有以下几个优点:

  1. 简单的二元逻辑:在过滤上下文中,查询子句根据是/否标准确定文档匹配项,而无需计算评分。
  2. 性能:由于它们不计算相关性评分,因此过滤器的执行速度比查询更快。
  3. 缓存:Elasticsearch 会自动缓存常用的过滤器,从而加快后续搜索性能。
  4. 资源效率:与全文查询相比,过滤器消耗的 CPU 资源更少。
  5. 查询组合:过滤器可以与评分查询组合使用,以有效地优化结果集。

过滤器在查询结构化数据和在复杂搜索中实现“必须具备”的条件时特别有效。

结构化数据是指以预定义的方式高度组织和格式化的信息。 在 Elasticsearch 的上下文中,这通常包括:

  • 数值字段(整数、浮点数)
  • 日期和时间戳
  • 布尔值
  • 关键词字段(精确匹配字符串)
  • 地理点和地理形状

与全文搜索字段不同,结构化数据具有一致的、可预测的格式,使其非常适合精确的过滤操作。

常见的过滤器应用包括:

  • 日期范围检查:例如 timestamp 字段是否在 2015 年和 2016 年之间
  • 特定的字段值检查:例如 status 字段是否等于“published”,或者 author 字段是否等于“John Doe”

当查询子句传递给 filter 参数时,例如以下参数时,会应用过滤上下文:

过滤器可以优化查询性能和效率,特别是对于结构化数据查询以及与全文搜索结合使用时。

查询和过滤上下文示例

编辑

以下是 search API 中在查询和过滤上下文中使用的查询子句示例。 此查询将匹配满足以下所有条件的文档:

  • title 字段包含单词 search
  • content 字段包含单词 elasticsearch
  • status 字段包含确切的单词 published
  • publish_date 字段包含 2015 年 1 月 1 日之后的日期。
$params = [
    'body' => [
        'query' => [
            'bool' => [
                'must' => [
                    [
                        'match' => [
                            'title' => 'Search',
                        ],
                    ],
                    [
                        'match' => [
                            'content' => 'Elasticsearch',
                        ],
                    ],
                ],
                'filter' => [
                    [
                        'term' => [
                            'status' => 'published',
                        ],
                    ],
                    [
                        'range' => [
                            'publish_date' => [
                                'gte' => '2015-01-01',
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    query={
        "bool": {
            "must": [
                {
                    "match": {
                        "title": "Search"
                    }
                },
                {
                    "match": {
                        "content": "Elasticsearch"
                    }
                }
            ],
            "filter": [
                {
                    "term": {
                        "status": "published"
                    }
                },
                {
                    "range": {
                        "publish_date": {
                            "gte": "2015-01-01"
                        }
                    }
                }
            ]
        }
    },
)
print(resp)
response = client.search(
  body: {
    query: {
      bool: {
        must: [
          {
            match: {
              title: 'Search'
            }
          },
          {
            match: {
              content: 'Elasticsearch'
            }
          }
        ],
        filter: [
          {
            term: {
              status: 'published'
            }
          },
          {
            range: {
              publish_date: {
                gte: '2015-01-01'
              }
            }
          }
        ]
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "bool": {
	      "must": [
	        {
	          "match": {
	            "title": "Search"
	          }
	        },
	        {
	          "match": {
	            "content": "Elasticsearch"
	          }
	        }
	      ],
	      "filter": [
	        {
	          "term": {
	            "status": "published"
	          }
	        },
	        {
	          "range": {
	            "publish_date": {
	              "gte": "2015-01-01"
	            }
	          }
	        }
	      ]
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  query: {
    bool: {
      must: [
        {
          match: {
            title: "Search",
          },
        },
        {
          match: {
            content: "Elasticsearch",
          },
        },
      ],
      filter: [
        {
          term: {
            status: "published",
          },
        },
        {
          range: {
            publish_date: {
              gte: "2015-01-01",
            },
          },
        },
      ],
    },
  },
});
console.log(response);
GET /_search
{
  "query": { 
    "bool": { 
      "must": [
        { "match": { "title":   "Search"        }},
        { "match": { "content": "Elasticsearch" }}
      ],
      "filter": [ 
        { "term":  { "status": "published" }},
        { "range": { "publish_date": { "gte": "2015-01-01" }}}
      ]
    }
  }
}

query 参数指示查询上下文。

bool 和两个 match 子句在查询上下文中使用,这意味着它们用于评分每个文档的匹配程度。

filter 参数指示过滤上下文。 它的 termrange 子句在过滤上下文中使用。 它们会过滤掉不匹配的文档,但不会影响匹配文档的评分。

在查询上下文中为查询计算的分数表示为单精度浮点数;它们只有 24 位有效数字的精度。 超过有效数字精度的分数计算将转换为精度损失的浮点数。

对于应影响匹配文档的分数(即文档的匹配程度)的条件,请在查询上下文中使用查询子句,并在过滤上下文中使用所有其他查询子句。