专业查询
edit专用查询
edit此组包含不适合归入其他组的查询:
-
distance_featurequery -
一个根据原点与文档的
date、date_nanos和geo_point字段之间的动态计算距离来计算分数的查询。 它能够有效地跳过非竞争性的命中。 -
more_like_thisquery - 此查询查找与指定文本、文档或文档集合相似的文档。
-
percolatequery - 此查询查找存储为与指定文档匹配的文档的查询。
-
rank_featurequery - 一个根据数值特征的值计算分数的查询,并且能够高效地跳过非竞争性的结果。
-
scriptquery -
此查询允许脚本充当过滤器。另请参见
function_score查询。 -
script_scorequery - 一个允许使用脚本修改子查询得分的查询。
-
wrapperquery - 一个接受其他查询作为json或yaml字符串的查询。
-
pinnedquery - 一种在给定查询中将选定文档优先于其他匹配文档的查询。
-
rulequery - 支持将基于查询的上下文规则(使用查询规则API定义)应用于给定查询的查询。
距离特征查询
edit提升接近提供的原点日期或点的文档的相关性分数。例如,您可以使用此查询来给予更接近某个日期或位置的文档更多权重。
您可以使用 distance_feature 查询来查找与某个位置最近的邻居。您还可以在 bool 搜索的 should 过滤器中使用该查询,以向 bool 查询的分数添加提升的相关性分数。
示例请求
edit索引设置
edit要使用 distance_feature 查询,您的索引必须包含一个 date、
date_nanos 或 geo_point 字段。
要查看如何为 distance_feature 查询设置索引,请尝试以下示例。
-
创建一个包含以下字段映射的
items索引:PUT /items { "mappings": { "properties": { "name": { "type": "keyword" }, "production_date": { "type": "date" }, "location": { "type": "geo_point" } } } } -
将多个文档索引到此索引中。
PUT /items/_doc/1?refresh { "name" : "chocolate", "production_date": "2018-02-01", "location": [-71.34, 41.12] } PUT /items/_doc/2?refresh { "name" : "chocolate", "production_date": "2018-01-01", "location": [-71.3, 41.15] } PUT /items/_doc/3?refresh { "name" : "chocolate", "production_date": "2017-12-01", "location": [-71.3, 41.12] }
示例查询
edit基于日期提升文档
edit以下 bool 搜索返回 name 值为 chocolate 的文档。该搜索还使用 distance_feature 查询来增加 production_date 值更接近 now 的文档的相关性分数。
GET /items/_search
{
"query": {
"bool": {
"must": {
"match": {
"name": "chocolate"
}
},
"should": {
"distance_feature": {
"field": "production_date",
"pivot": "7d",
"origin": "now"
}
}
}
}
}
基于位置提升文档
edit以下 bool 搜索返回 name 值为 chocolate 的文档。该搜索还使用 distance_feature 查询来增加 location 值更接近 [-71.3, 41.15] 的文档的相关性分数。
GET /items/_search
{
"query": {
"bool": {
"must": {
"match": {
"name": "chocolate"
}
},
"should": {
"distance_feature": {
"field": "location",
"pivot": "1000m",
"origin": [-71.3, 41.15]
}
}
}
}
}
用于distance_feature的顶级参数
edit-
field -
(必需,字符串)用于计算距离的字段名称。此字段必须满足以下条件:
-
是一个
date、date_nanos或geo_point字段 -
具有
index映射参数值为true,这是默认值 -
具有
doc_values映射参数值为true,这也是默认值
-
是一个
-
origin -
(必需,字符串) 用于计算距离的日期或起始点。
如果
field值是date或date_nanos字段,则origin值必须是 日期。 支持 日期数学,例如now-1h。如果
field的值是一个geo_point字段,那么origin的值必须是一个地理点。 -
pivot -
(必需,时间单位 或 距离单位) 距离
origin的距离,在此距离处相关性得分将获得boost值的一半。如果
field的值是date或date_nanos字段,pivot的值必须是 时间单位,例如1h或10d。 -
boost -
(可选, 浮点数) 用于乘以匹配文档的相关性分数的浮点数。此值不能为负数。默认为
1.0。
注释
edit如何计算distance_feature查询的相关性分数
editThe distance_feature query 动态计算 origin 值与文档字段值之间的距离。然后使用此距离作为特征来提升更接近文档的 相关性分数。
The distance_feature query 计算文档的
相关性分数 如下:
relevance score = boost * pivot / (pivot + distance)
The distance 是 origin 值与文档字段值之间的绝对差值。
跳过非竞争性命中
edit与function_score查询或其他改变相关性分数的方式不同,distance_feature查询在track_total_hits参数不是true时,能够高效地跳过非竞争性的命中结果。
更多类似此查询
editMore Like This 查询用于查找与给定文档集“相似”的文档。为此,MLT 会选择这些输入文档的一组代表性术语,使用这些术语形成查询,执行查询并返回结果。用户可以控制输入文档、术语的选择方式以及查询的形成方式。
最简单的用例包括请求与提供的文本片段相似的文档。在这里,我们请求所有在其“标题”和“描述”字段中包含与“很久以前”相似文本的电影,并将选定的条目数量限制为12个。
GET /_search
{
"query": {
"more_like_this" : {
"fields" : ["title", "description"],
"like" : "Once upon a time",
"min_term_freq" : 1,
"max_query_terms" : 12
}
}
}
一个更复杂的用例包括将文本与索引中已存在的文档混合。在这种情况下,指定文档的语法与Multi GET API中使用的语法类似。
GET /_search
{
"query": {
"more_like_this": {
"fields": [ "title", "description" ],
"like": [
{
"_index": "imdb",
"_id": "1"
},
{
"_index": "imdb",
"_id": "2"
},
"and potentially some more text here as well"
],
"min_term_freq": 1,
"max_query_terms": 12
}
}
}
最后,用户可以混合一些文本、一组选定的文档,还可以提供不一定存在于索引中的文档。要提供不存在于索引中的文档,语法类似于人工文档。
GET /_search
{
"query": {
"more_like_this": {
"fields": [ "name.first", "name.last" ],
"like": [
{
"_index": "marvel",
"doc": {
"name": {
"first": "Ben",
"last": "Grimm"
},
"_doc": "You got no idea what I'd... what I'd give to be invisible."
}
},
{
"_index": "marvel",
"_id": "2"
}
],
"min_term_freq": 1,
"max_query_terms": 12
}
}
}
工作原理
edit假设我们想要找到与给定输入文档相似的所有文档。显然,对于这种类型的查询,输入文档本身应该是其最佳匹配。原因主要是根据Lucene评分公式,由于具有最高tf-idf的术语。因此,输入文档中具有最高tf-idf的术语是该文档的良好代表,并且可以在析取查询(或OR)中使用以检索相似文档。MLT查询简单地从输入文档中提取文本,对其进行分析,通常使用与字段相同的分析器,然后选择具有最高tf-idf的前K个术语来形成这些术语的析取查询。
要执行MLT的字段必须被索引并且类型为text或keyword。此外,当使用like与文档时,必须启用_source或字段必须被stored或存储term_vector。为了加快分析速度,在索引时存储词向量可能会有所帮助。
例如,如果我们希望对“title”和“tags.raw”字段执行MLT,我们可以在索引时显式存储它们的term_vector。我们仍然可以对“description”和“tags”字段执行MLT,因为默认情况下启用了_source,但对于这些字段,分析速度不会加快。
PUT /imdb
{
"mappings": {
"properties": {
"title": {
"type": "text",
"term_vector": "yes"
},
"description": {
"type": "text"
},
"tags": {
"type": "text",
"fields": {
"raw": {
"type": "text",
"analyzer": "keyword",
"term_vector": "yes"
}
}
}
}
}
}
参数
edit唯一必需的参数是like,所有其他参数都有合理的默认值。参数分为三种类型:一种用于指定文档输入,另一种用于术语选择和查询形成。
文档输入参数
edit|
|
MLT查询的唯一必需参数是 |
|
|
|
|
|
要获取和分析文本的字段列表。默认为
|
术语选择参数
edit|
|
将选择的查询词的最大数量。增加此值会以查询执行速度为代价提高准确性。默认为
|
|
|
输入文档中低于此最小词频的词将被忽略。默认为 |
|
|
输入文档中低于此最小文档频率的术语将被忽略。默认为 |
|
|
输入文档中将被忽略的术语的最大文档频率。这可能有助于忽略高频词,例如停用词。默认为无界( |
|
|
低于此最小字长阈值的词条将被忽略。默认为 |
|
|
忽略术语的最大词长度。默认为无限制( |
|
|
一组停用词。在此集合中的任何单词都被认为是“无趣的”并被忽略。如果分析器允许使用停用词,您可能希望告诉MLT明确忽略它们,因为在文档相似性的目的下,假设“停用词永远不有趣”似乎是合理的。 |
|
|
用于分析自由格式文本的分析器。默认使用与 |
查询形成参数
edit|
|
在析取查询形成后,此参数控制必须匹配的术语数量。
语法与最小应匹配相同。
(默认值为 |
|
|
控制查询是否应在任何指定的字段不是支持的类型( |
|
|
形成的查询中的每个术语可以通过其tf-idf分数进一步增强。
这设置了使用此功能时的增强因子。默认为
未激活( |
|
|
指定输入的文档是否也应包含在返回的搜索结果中。默认为 |
|
|
设置整个查询的提升值。默认为 |
替代方案
edit为了更精细地控制构建用于查找相似文档的查询,值得考虑编写自定义客户端代码,将示例文档中的选定术语组装成具有所需设置的布尔查询。more_like_this 中用于从一段文本中选择“有趣”单词的逻辑也可以通过 TermVectors API 访问。例如,使用 termvectors API,可以向用户展示文档文本中发现的主题关键词,允许他们选择感兴趣的词语进行深入挖掘,而不是使用 more_like_this 所采用的更“黑箱”的匹配方法。
percolate 查询
editThe percolate 查询可以用于匹配存储在索引中的查询。percolate 查询本身包含将被用作查询的文档,以与存储的查询进行匹配。
示例用法
edit为了提供一个简单的示例,本文档使用一个索引,
my-index-000001,用于存储 percolate 查询和文档。当只注册了少量 percolate 查询时,这种设置可以很好地工作。对于更重的使用场景,我们建议您将查询和文档存储在不同的索引中。有关更多详细信息,请参阅 How it Works Under the Hood。
创建一个包含两个字段的索引:
PUT /my-index-000001
{
"mappings": {
"properties": {
"message": {
"type": "text"
},
"query": {
"type": "percolator"
}
}
}
}
The message 字段是用于在将文档定义的 percolator 查询预处理后,将其索引到临时索引中的字段。
The query 字段用于索引查询文档。它将保存一个表示实际 Elasticsearch 查询的 json 对象。query 字段已配置为使用 percolator 字段类型。此字段类型理解查询 DSL 并以一种可以在以后用于匹配 percolate 查询中定义的文档的方式存储查询。
在 percolator 中注册一个查询:
PUT /my-index-000001/_doc/1?refresh
{
"query": {
"match": {
"message": "bonsai tree"
}
}
}
将文档与已注册的 percolator 查询进行匹配:
GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"document": {
"message": "A new bonsai tree in the office"
}
}
}
}
上述请求将产生以下响应:
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.26152915,
"hits": [
{
"_index": "my-index-000001",
"_id": "1",
"_score": 0.26152915,
"_source": {
"query": {
"match": {
"message": "bonsai tree"
}
}
},
"fields" : {
"_percolator_document_slot" : [0]
}
}
]
}
}
参数
edit以下参数在渗透文档时是必需的:
|
|
类型为 |
|
|
在指定了多个 |
|
|
正在渗透的文档的来源。 |
|
|
类似于 |
|
|
正在被 percolated 的文档的类型 / 映射。此参数已弃用,并将在 Elasticsearch 8.0 中移除。 |
不需要指定被筛选文档的来源,也可以从已存储的文档中获取来源。percolate 查询将在内部执行一个获取请求来获取该文档。
在这种情况下,document 参数可以用以下参数替代:
|
|
文档所在的索引。这是一个必需的参数。 |
|
|
要获取的文档类型。此参数已弃用,并将在 Elasticsearch 8.0 中移除。 |
|
|
要获取的文档的ID。这是一个必需的参数。 |
|
|
可选地,使用路由来获取要过滤的文档。 |
|
|
可选地,用于获取要过滤的文档的偏好。 |
|
|
可选地,要获取的文档的预期版本。 |
在过滤上下文中的渗透
edit如果你对分数不感兴趣,可以通过将 percolator 查询包装在 bool 查询的过滤子句中或在一个 constant_score 查询中来获得更好的性能:
GET /my-index-000001/_search
{
"query": {
"constant_score": {
"filter": {
"percolate": {
"field": "query",
"document": {
"message": "A new bonsai tree in the office"
}
}
}
}
}
}
在索引时,术语从percolator查询中提取,percolator通常可以通过查看这些提取的术语来确定查询是否匹配。然而,计算分数需要反序列化每个匹配的查询并将其与渗透的文档进行比较,这是一个更昂贵的操作。因此,如果不需要计算分数,percolate查询应该被包装在一个constant_score查询或bool查询的过滤子句中。
请注意,percolate 查询永远不会被查询缓存所缓存。
渗透多个文档
editThe percolate 查询可以使用索引的 percolator 查询同时匹配多个文档。
在单个请求中 percolating 多个文档可以提高性能,因为查询只需要解析和匹配一次,而不是多次。
当同时过滤多个文档时,与每个匹配的过滤器查询一起返回的_percolator_document_slot字段非常重要。它指示哪些文档与特定的过滤器查询匹配。这些数字与percolate查询中指定的documents数组中的槽相关联。
GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"documents": [
{
"message": "bonsai tree"
},
{
"message": "new tree"
},
{
"message": "the office"
},
{
"message": "office tree"
}
]
}
}
}
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.7093853,
"hits": [
{
"_index": "my-index-000001",
"_id": "1",
"_score": 0.7093853,
"_source": {
"query": {
"match": {
"message": "bonsai tree"
}
}
},
"fields" : {
"_percolator_document_slot" : [0, 1, 3]
}
}
]
}
}
渗透现有文档
edit为了过滤新索引的文档,可以使用percolate查询。根据索引请求的响应,可以使用_id和其他元信息立即过滤新添加的文档。
示例
edit基于前面的示例。
索引我们想要渗透的文档:
PUT /my-index-000001/_doc/2
{
"message" : "A new bonsai tree in the office"
}
索引响应:
{
"_index": "my-index-000001",
"_id": "2",
"_version": 1,
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"result": "created",
"_seq_no" : 1,
"_primary_term" : 1
}
使用索引响应作为基础来构建新的搜索请求,对现有文档进行渗透:
GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"index": "my-index-000001",
"id": "2",
"version": 1
}
}
}
搜索响应返回的内容与前一个示例相同。
渗透查询和突出显示
edit当涉及到高亮显示时,percolate 查询的处理方式是特殊的。查询的命中结果用于高亮显示在 percolate 查询中提供的文档。而在常规的高亮显示中,搜索请求中的查询用于高亮显示命中结果。
示例
edit此示例基于第一个示例的映射。
保存查询:
PUT /my-index-000001/_doc/3?refresh
{
"query": {
"match": {
"message": "brown fox"
}
}
}
保存另一个查询:
PUT /my-index-000001/_doc/4?refresh
{
"query": {
"match": {
"message": "lazy dog"
}
}
}
执行一个带有percolate查询和启用高亮的搜索请求:
GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"document": {
"message": "The quick brown fox jumps over the lazy dog"
}
}
},
"highlight": {
"fields": {
"message": {}
}
}
}
这将产生以下响应。
{
"took": 7,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 2,
"relation": "eq"
},
"max_score": 0.26152915,
"hits": [
{
"_index": "my-index-000001",
"_id": "3",
"_score": 0.26152915,
"_source": {
"query": {
"match": {
"message": "brown fox"
}
}
},
"highlight": {
"message": [
"The quick <em>brown</em> <em>fox</em> jumps over the lazy dog"
]
},
"fields" : {
"_percolator_document_slot" : [0]
}
},
{
"_index": "my-index-000001",
"_id": "4",
"_score": 0.26152915,
"_source": {
"query": {
"match": {
"message": "lazy dog"
}
}
},
"highlight": {
"message": [
"The quick brown fox jumps over the <em>lazy</em> <em>dog</em>"
]
},
"fields" : {
"_percolator_document_slot" : [0]
}
}
]
}
}
与在搜索请求中高亮显示 percolator 命中的查询不同,percolator 查询会高亮显示在 percolate 查询中定义的文档。
当同时渗透多个文档时,如下面的请求所示,高亮响应会有所不同:
GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"documents": [
{
"message": "bonsai tree"
},
{
"message": "new tree"
},
{
"message": "the office"
},
{
"message": "office tree"
}
]
}
},
"highlight": {
"fields": {
"message": {}
}
}
}
稍微不同的响应:
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.7093853,
"hits": [
{
"_index": "my-index-000001",
"_id": "1",
"_score": 0.7093853,
"_source": {
"query": {
"match": {
"message": "bonsai tree"
}
}
},
"fields" : {
"_percolator_document_slot" : [0, 1, 3]
},
"highlight" : {
"0_message" : [
"<em>bonsai</em> <em>tree</em>"
],
"3_message" : [
"office <em>tree</em>"
],
"1_message" : [
"new <em>tree</em>"
]
}
}
]
}
}
在 percolator 查询中的命名查询
edit如果一个存储的 percolator 查询是一个复杂查询,并且您想要跟踪其子查询匹配了哪个 percolated 文档,那么您可以使用其子查询的 \_name 参数。在这种情况下,在响应中,每个命中连同 _percolator_document_slot 字段一起包含 _percolator_document_slot_ 字段,这些字段显示了哪些子查询匹配了每个 percolated 文档。
例如:
PUT /my-index-000001/_doc/5?refresh
{
"query": {
"bool": {
"should": [
{
"match": {
"message": {
"query": "Japanese art",
"_name": "query1"
}
}
},
{
"match": {
"message": {
"query": "Holand culture",
"_name": "query2"
}
}
}
]
}
}
}
GET /my-index-000001/_search
{
"query": {
"percolate": {
"field": "query",
"documents": [
{
"message": "Japanse art"
},
{
"message": "Holand culture"
},
{
"message": "Japanese art and Holand culture"
},
{
"message": "no-match"
}
]
}
}
}
{
"took": 55,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 1.1181908,
"hits": [
{
"_index": "my-index-000001",
"_id": "5",
"_score": 1.1181908,
"_source": {
"query": {
"bool": {
"should": [
{
"match": {
"message": {
"query": "Japanese art",
"_name": "query1"
}
}
},
{
"match": {
"message": {
"query": "Holand culture",
"_name": "query2"
}
}
}
]
}
}
},
"fields" : {
"_percolator_document_slot" : [0, 1, 2],
"_percolator_document_slot_0_matched_queries" : ["query1"],
"_percolator_document_slot_1_matched_queries" : ["query2"],
"_percolator_document_slot_2_matched_queries" : ["query1", "query2"]
}
}
]
}
}
指定多个渗透查询
edit可以在单个搜索请求中指定多个percolate查询:
GET /my-index-000001/_search
{
"query": {
"bool": {
"should": [
{
"percolate": {
"field": "query",
"document": {
"message": "bonsai tree"
},
"name": "query1"
}
},
{
"percolate": {
"field": "query",
"document": {
"message": "tulip flower"
},
"name": "query2"
}
}
]
}
}
}
字段名称 _percolator_document_slot 将附加在 _name 参数中指定的内容之后。
如果没有指定,则将使用 field 参数,在这种情况下会导致歧义。
上述搜索请求返回的响应类似于以下内容:
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.26152915,
"hits": [
{
"_index": "my-index-000001",
"_id": "1",
"_score": 0.26152915,
"_source": {
"query": {
"match": {
"message": "bonsai tree"
}
}
},
"fields" : {
"_percolator_document_slot_query1" : [0]
}
}
]
}
}
工作原理揭秘
edit当将文档索引到一个已配置了percolator字段类型映射的索引时,文档的查询部分会被解析为Lucene查询并存储到Lucene索引中。查询的二进制表示形式会被存储,但查询的术语也会被分析并存储到一个索引字段中。
在搜索时,请求中指定的文档会被解析为Lucene文档并存储在内存中的临时Lucene索引中。这个内存中的索引只能保存这一个文档,并且针对此进行了优化。之后,基于内存索引中的术语构建一个特殊查询,该查询根据其索引的查询术语选择候选的percolator查询。然后,内存索引会评估这些查询是否实际匹配。
选择候选渗透器查询匹配项是执行percolate查询期间的一个重要性能优化,因为它可以显著减少内存索引需要评估的候选匹配项数量。percolate查询能够实现这一点的原因是,在索引渗透器查询期间,查询词被提取并与渗透器查询一起索引。不幸的是,渗透器无法从所有查询中提取词(例如wildcard或geo_shape查询),因此在某些情况下,渗透器无法进行选择优化(例如,如果布尔查询的必需子句中定义了不支持的查询,或者渗透器文档中唯一查询是不支持的查询)。这些查询被渗透器标记,可以通过运行以下搜索来找到:
GET /_search
{
"query": {
"term" : {
"query.extraction_result" : "failed"
}
}
}
上述示例假设映射中存在一个类型为 percolator 的 query 字段。
鉴于渗透设计,通常使用单独的索引来存储渗透查询和被渗透的文档是有意义的,而不是像我们在示例中那样使用单一索引。这种方法有几个好处:
- 因为 percolate 查询包含与 percolated 文档不同的字段集,使用两个单独的索引可以更密集、更高效地存储字段。
- Percolate 查询的扩展方式与其他查询不同,因此使用不同的索引配置(如主分片数量)可能会提高 percolation 性能。
注释
edit允许昂贵的查询
edit如果 search.allow_expensive_queries 设置为 false,则不会执行 percolate 查询。
排名特征查询
edit基于rank_feature或rank_features字段的数值,提升文档的相关性评分。
The rank_feature 查询通常用于 bool 查询的 should 子句中,以便将其相关性评分添加到 bool 查询中的其他评分中。
对于rank_feature或rank_features字段,如果positive_score_impact设置为false,我们建议参与查询的每个文档都为此字段设置一个值。否则,如果在should子句中使用了rank_feature查询,它不会为缺少该值的文档增加任何分数,但会为包含该特征的文档增加一些提升。这与我们想要的相反——因为我们认为这些特征是负面的,我们希望将包含它们的文档排名低于缺少它们的文档。
与function_score查询或其他改变相关性分数的方法不同,rank_feature查询在track_total_hits参数不是true时,能够高效地跳过非竞争性的命中结果。这可以显著提高查询速度。
排名特征函数
edit要基于排名特征字段计算相关性得分,rank_feature查询支持以下数学函数:
如果你不知道从哪里开始,我们推荐使用saturation函数。如果没有提供函数,rank_feature查询默认使用saturation函数。
示例请求
edit索引设置
edit要使用 rank_feature 查询,您的索引必须包含一个
rank_feature 或 rank_features 字段映射。要了解如何为 rank_feature 查询设置索引,请尝试以下示例。
创建一个包含以下字段映射的 test 索引:
-
pagerank,一个rank_feature字段,用于衡量网站的重要性 -
url_length,一个rank_feature字段,包含网站URL的长度。在这个例子中,长URL与相关性呈负相关,由positive_score_impact值为false表示。 -
topics,一个rank_features字段,包含一个主题列表以及每个文档与该主题的连接程度的度量
PUT /test
{
"mappings": {
"properties": {
"pagerank": {
"type": "rank_feature"
},
"url_length": {
"type": "rank_feature",
"positive_score_impact": false
},
"topics": {
"type": "rank_features"
}
}
}
}
将多个文档索引到test索引中。
PUT /test/_doc/1?refresh
{
"url": "https://en.wikipedia.org/wiki/2016_Summer_Olympics",
"content": "Rio 2016",
"pagerank": 50.3,
"url_length": 42,
"topics": {
"sports": 50,
"brazil": 30
}
}
PUT /test/_doc/2?refresh
{
"url": "https://en.wikipedia.org/wiki/2016_Brazilian_Grand_Prix",
"content": "Formula One motor race held on 13 November 2016",
"pagerank": 50.3,
"url_length": 47,
"topics": {
"sports": 35,
"formula one": 65,
"brazil": 20
}
}
PUT /test/_doc/3?refresh
{
"url": "https://en.wikipedia.org/wiki/Deadpool_(film)",
"content": "Deadpool is a 2016 American superhero film",
"pagerank": 50.3,
"url_length": 37,
"topics": {
"movies": 60,
"super hero": 65
}
}
示例查询
edit以下查询搜索 2016 并根据 pagerank、url_length 和 sports 主题提升相关性分数。
GET /test/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"content": "2016"
}
}
],
"should": [
{
"rank_feature": {
"field": "pagerank"
}
},
{
"rank_feature": {
"field": "url_length",
"boost": 0.1
}
},
{
"rank_feature": {
"field": "topics.sports",
"boost": 0.4
}
}
]
}
}
}
用于rank_feature的顶级参数
edit-
field -
(必需,字符串) 用于提升
rank_feature或rank_features字段的 相关性评分。 -
boost -
(可选, 浮点数) 用于减少或增加 相关性分数的浮点数。默认为
1.0。Boost值相对于默认值
1.0是相对的。Boost值在0和1.0之间会降低相关性分数。大于1.0的值会增加相关性分数。 -
saturation -
(可选, 函数对象) 用于基于排名特征
字段的值来提升相关性分数的饱和函数。如果没有提供函数,rank_feature查询默认使用saturation函数。更多信息请参见饱和度。只能提供一个函数
saturation、log、sigmoid或linear。 -
log -
(可选, 函数对象) 对数函数用于基于排名特征
字段的值来提升相关性分数。更多信息请参见对数。只能提供一个函数
saturation、log、sigmoid或linear。 -
sigmoid -
(可选, 函数对象) 用于基于排名特征
field的值提升相关性分数的Sigmoid函数。更多信息请参见Sigmoid。只能提供一个函数
saturation、log、sigmoid或linear。 -
linear -
(可选, 函数对象) 用于基于排名特征
字段的值提升相关性分数的线性函数。更多信息请参见线性。只能提供一个函数
saturation、log、sigmoid或linear。
注释
edit饱和度
editThe saturation 函数给出一个等于 S / (S + pivot) 的分数,其中 S 是
排名特征字段的值,pivot 是一个可配置的枢轴值,
因此如果 S 小于枢轴,结果将小于 0.5,否则将大于
0.5。分数总是 (0,1)。
如果排名特征对分数有负面影响,那么函数将计算为 pivot / (S + pivot),随着 S 的增加而减少。
GET /test/_search
{
"query": {
"rank_feature": {
"field": "pagerank",
"saturation": {
"pivot": 8
}
}
}
}
如果没有提供pivot值,Elasticsearch会计算一个默认值,该值等于索引中所有rank feature值的近似几何平均值。如果你没有机会训练一个好的pivot值,我们建议使用这个默认值。
GET /test/_search
{
"query": {
"rank_feature": {
"field": "pagerank",
"saturation": {}
}
}
}
对数
editThe log 函数给出一个等于 log(scaling_factor + S) 的分数,其中 S 是排名特征字段的值,scaling_factor 是一个可配置的缩放因子。分数是无界的。
此函数仅支持对得分有正面影响的排名特征。
GET /test/_search
{
"query": {
"rank_feature": {
"field": "pagerank",
"log": {
"scaling_factor": 4
}
}
}
}
Sigmoid
editThe sigmoid 函数是 saturation 的扩展,它增加了一个可配置的指数。分数的计算公式为 S^exp^ / (S^exp^ + pivot^exp^)。与 saturation 函数类似,pivot 是使分数为 0.5 的 S 值,分数范围为 (0,1)。
指数exponent必须为正数,通常在[0.5, 1]范围内。一个好的值应该通过训练来计算。如果你没有机会这样做,我们建议你使用saturation函数代替。
GET /test/_search
{
"query": {
"rank_feature": {
"field": "pagerank",
"sigmoid": {
"pivot": 7,
"exponent": 0.6
}
}
}
}
线性
editThe linear 函数是最简单的函数,并且给出的分数等于 S 的索引值,其中 S 是 rank feature 字段的值。
如果一个 rank feature 字段被索引为 "positive_score_impact": true,
它的索引值等于 S 并且四舍五入以保留仅 9 位有效位以保证精度。
如果一个 rank feature 字段被索引为 "positive_score_impact": false,
它的索引值等于 1/S 并且四舍五入以保留仅 9 位有效位以保证精度。
GET /test/_search
{
"query": {
"rank_feature": {
"field": "pagerank",
"linear": {}
}
}
}
脚本查询
edit根据提供的脚本过滤文档。script查询通常用于过滤上下文中。
使用脚本可能导致搜索速度变慢。请参阅 脚本、缓存和搜索速度。
示例请求
editGET /_search
{
"query": {
"bool": {
"filter": {
"script": {
"script": """
double amount = doc['amount'].value;
if (doc['type'].value == 'expense') {
amount *= -1;
}
return amount < 10;
"""
}
}
}
}
}
您可以通过使用运行时字段在搜索查询中实现相同的结果。使用fields参数在_search API上获取作为同一查询一部分的值:
GET /_search
{
"runtime_mappings": {
"amount.signed": {
"type": "double",
"script": """
double amount = doc['amount'].value;
if (doc['type'].value == 'expense') {
amount *= -1;
}
emit(amount);
"""
}
},
"query": {
"bool": {
"filter": {
"range": {
"amount.signed": { "lt": 10 }
}
}
}
},
"fields": [{"field": "amount.signed"}]
}
注释
edit自定义参数
edit与过滤器一样,脚本会被缓存以加快执行速度。
如果您频繁更改脚本的参数,我们建议您将它们存储在脚本的params参数中。例如:
GET /_search
{
"query": {
"bool": {
"filter": {
"script": {
"script": {
"source": "doc['num1'].value > params.param1",
"lang": "painless",
"params": {
"param1": 5
}
}
}
}
}
}
}
允许昂贵的查询
edit如果 search.allow_expensive_queries 设置为 false,脚本查询将不会被执行。
脚本评分查询
edit使用一个脚本为返回的文档提供自定义评分。
如果例如,一个评分函数很昂贵,并且你只需要计算过滤后的文档集的分数,那么script_score查询就很有用。
示例请求
edit以下 script_score 查询为每个返回的文档分配一个分数,该分数等于 my-int 字段值除以 10。
GET /_search
{
"query": {
"script_score": {
"query": {
"match": { "message": "elasticsearch" }
},
"script": {
"source": "doc['my-int'].value / 10 "
}
}
}
}
用于script_score的顶级参数
edit-
query - (必需,查询对象) 用于返回文档的查询。
-
script -
(必需的, 脚本对象) 用于计算由
query返回的文档的分数的脚本。来自
script_score查询的最终相关性评分不能为负数。为了支持某些搜索优化,Lucene 要求评分必须为正数或0。 -
min_score - (可选, 浮点数) 得分低于此浮点数的文档将从搜索结果中排除。
-
boost -
(可选, 浮点数) 由
script生成的文档分数会乘以boost以生成最终的文档分数。默认为1.0。
注释
edit预定义函数
edit您可以在您的script中使用任何可用的painless函数。您还可以使用以下预定义函数来自定义评分:
我们建议使用这些预定义函数,而不是编写自己的函数。 这些函数利用了 Elasticsearch 内部机制的效率。
饱和度
editsaturation(value,k) = value/(k + value)
"script" : {
"source" : "saturation(doc['my-int'].value, 1)"
}
Sigmoid
editsigmoid(value, k, a) = value^a/ (k^a + value^a)
"script" : {
"source" : "sigmoid(doc['my-int'].value, 2, 1)"
}
随机评分函数
editrandom_score 函数生成从0到1(不包括1)均匀分布的分数。
randomScore 函数具有以下语法:
randomScore(。
它有一个必需的参数 - seed 作为整数值,
和一个可选的参数 - fieldName 作为字符串值。
"script" : {
"source" : "randomScore(100, '_seq_no')"
}
如果省略了fieldName参数,将使用内部Lucene文档ID作为随机性的来源。这是非常高效的,但不幸的是,由于文档可能会在合并过程中重新编号,因此无法重现。
"script" : {
"source" : "randomScore(100)"
}
请注意,位于同一分片中且具有相同字段值的文档将获得相同的分数,因此通常希望使用一个在分片中的所有文档中具有唯一值的字段。一个好的默认选择可能是使用_seq_no字段,其唯一缺点是如果文档被更新,分数将会改变,因为更新操作也会更新_seq_no字段的值。
数值字段的衰减函数
edit您可以在此处阅读更多关于衰减函数的信息 here.
-
double decayNumericLinear(double origin, double scale, double offset, double decay, double docValue) -
double decayNumericExp(double origin, double scale, double offset, double decay, double docValue) -
double decayNumericGauss(double origin, double scale, double offset, double decay, double docValue)
地理字段的衰减函数
edit-
double decayGeoLinear(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue) -
double decayGeoExp(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue) -
double decayGeoGauss(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)
"script" : {
"source" : "decayGeoExp(params.origin, params.scale, params.offset, params.decay, doc['location'].value)",
"params": {
"origin": "40, -70.12",
"scale": "200km",
"offset": "0km",
"decay" : 0.2
}
}
日期字段的衰减函数
edit-
double decayDateLinear(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate) -
double decayDateExp(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate) -
double decayDateGauss(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)
"script" : {
"source" : "decayDateGauss(params.origin, params.scale, params.offset, params.decay, doc['date'].value)",
"params": {
"origin": "2008-01-01T01:00:00Z",
"scale": "1h",
"offset" : "0",
"decay" : 0.5
}
}
日期上的衰减函数仅限于默认格式和默认时区的日期。此外,不支持使用now进行计算。
允许昂贵的查询
edit如果 search.allow_expensive_queries 设置为 false,脚本评分查询将不会被执行。
更快的替代方案
editThe script_score 查询计算每个匹配文档或命中的分数。有一些更快的替代查询类型可以有效地跳过非竞争性命中:
-
如果你想在某些静态字段上提升文档的排名,请使用
rank_feature查询。 -
如果你想提升更接近某个日期或地理位置的文档的排名,请使用
distance_feature查询。
从函数评分查询的过渡
edit我们建议使用 script_score 查询,而不是 function_score 查询,因为 script_score 查询更简单。
您可以使用 script_score 查询来实现 function_score 查询的以下功能:
script_score
edit在 Function Score 查询中使用的 script_score,你可以直接复制到 Script Score 查询中。这里不需要做任何改动。
weight
editweight 函数可以通过以下脚本在 Script Score 查询中实现:
"script" : {
"source" : "params.weight * _score",
"params": {
"weight": 2
}
}
field_value_factor
editfield_value_factor 函数可以通过脚本轻松实现:
"script" : {
"source" : "Math.log10(doc['field'].value * params.factor)",
"params" : {
"factor" : 5
}
}
要检查文档是否缺少某个值,可以使用
doc['field'].size() == 0。例如,如果文档没有字段 field,此脚本将使用值 1:
"script" : {
"source" : "Math.log10((doc['field'].size() == 0 ? 1 : doc['field'].value()) * params.factor)",
"params" : {
"factor" : 5
}
}
此表列出了如何通过脚本实现 field_value_factor 修饰符:
| Modifier | Implementation in Script Score |
|---|---|
|
- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
衰减函数
editThe script_score query has equivalent decay
functions that can be used in scripts.
向量字段的函数
edit在向量函数的计算过程中,所有匹配的文档都会被线性扫描。因此,查询时间会随着匹配文档数量的增加而线性增长。出于这个原因,我们建议使用query参数来限制匹配文档的数量。
这是可用向量函数和向量访问方法的列表:
-
cosineSimilarity– 计算余弦相似度 -
dotProduct– 计算点积 -
l1norm– 计算L1距离 -
hamming– 计算汉明距离 -
l2norm- 计算L2距离 -
doc[– 返回向量的值作为浮点数数组].vectorValue -
doc[– 返回向量的幅度].magnitude
对于bit向量,不支持cosineSimilarity和dotProduct函数。
访问密集向量的推荐方法是使用
cosineSimilarity、dotProduct、l1norm 或 l2norm 函数。但请注意,您应该在每个脚本中仅调用这些函数一次。例如,不要在循环中使用这些函数来计算文档向量与多个其他向量之间的相似性。如果您需要该功能,请通过
直接访问向量值 自行重新实现这些函数。
让我们创建一个带有 dense_vector 映射的索引,并将其索引几个文档。
PUT my-index-000001
{
"mappings": {
"properties": {
"my_dense_vector": {
"type": "dense_vector",
"index": false,
"dims": 3
},
"my_byte_dense_vector": {
"type": "dense_vector",
"index": false,
"dims": 3,
"element_type": "byte"
},
"status" : {
"type" : "keyword"
}
}
}
}
PUT my-index-000001/_doc/1
{
"my_dense_vector": [0.5, 10, 6],
"my_byte_dense_vector": [0, 10, 6],
"status" : "published"
}
PUT my-index-000001/_doc/2
{
"my_dense_vector": [-0.5, 10, 10],
"my_byte_dense_vector": [0, 10, 10],
"status" : "published"
}
POST my-index-000001/_refresh
余弦相似度
edit函数 cosineSimilarity 计算给定查询向量与文档向量之间的余弦相似度度量。
GET my-index-000001/_search
{
"query": {
"script_score": {
"query" : {
"bool" : {
"filter" : {
"term" : {
"status" : "published"
}
}
}
},
"script": {
"source": "cosineSimilarity(params.query_vector, 'my_dense_vector') + 1.0",
"params": {
"query_vector": [4, 3.4, -0.2]
}
}
}
}
}
如果文档的密集向量字段的维度数量与查询向量的维度不同,将会抛出一个错误。
点积
edit函数 dotProduct 计算给定查询向量与文档向量之间的点积度量。
GET my-index-000001/_search
{
"query": {
"script_score": {
"query" : {
"bool" : {
"filter" : {
"term" : {
"status" : "published"
}
}
}
},
"script": {
"source": """
double value = dotProduct(params.query_vector, 'my_dense_vector');
return sigmoid(1, Math.E, -value);
""",
"params": {
"query_vector": [4, 3.4, -0.2]
}
}
}
}
}
L1距离(曼哈顿距离)
edit函数 l1norm 计算给定查询向量和文档向量之间的 L1 距离(曼哈顿距离)。
汉明距离
edit函数计算给定查询向量与文档向量之间的汉明距离。它仅适用于字节和位向量。
L2距离(欧几里得距离)
edit函数 l2norm 计算给定查询向量与文档向量之间的 L2 距离(欧几里得距离)。
GET my-index-000001/_search
{
"query": {
"script_score": {
"query" : {
"bool" : {
"filter" : {
"term" : {
"status" : "published"
}
}
}
},
"script": {
"source": "1 / (1 + l2norm(params.queryVector, 'my_dense_vector'))",
"params": {
"queryVector": [4, 3.4, -0.2]
}
}
}
}
}
检查缺失值
edit如果文档在执行向量函数的向量字段上没有值,将会抛出一个错误。
你可以检查一个文档是否在字段 my_vector 上有值,使用 doc['my_vector'].size() == 0。你的整体脚本可以看起来像这样:
"source": "doc['my_vector'].size() == 0 ? 0 : cosineSimilarity(params.queryVector, 'my_vector')"
直接访问向量
edit您可以通过以下函数直接访问向量值:
-
doc[– 返回一个向量的值作为浮点数数组].vectorValue
对于位向量,它返回一个浮点数[],其中每个元素代表8位。
-
doc[– 返回一个向量的幅度作为浮点数 (对于7.5版本之前创建的向量,幅度不会被存储。 因此,每次调用此函数时都会重新计算)。].magnitude
对于位向量,这只是1位总和的平方根。
例如,下面的脚本使用这两个函数实现了余弦相似度:
GET my-index-000001/_search
{
"query": {
"script_score": {
"query" : {
"bool" : {
"filter" : {
"term" : {
"status" : "published"
}
}
}
},
"script": {
"source": """
float[] v = doc['my_dense_vector'].vectorValue;
float vm = doc['my_dense_vector'].magnitude;
float dotProduct = 0;
for (int i = 0; i < v.length; i++) {
dotProduct += v[i] * params.queryVector[i];
}
return dotProduct / (vm * (float) params.queryVectorMag);
""",
"params": {
"queryVector": [4, 3.4, -0.2],
"queryVectorMag": 5.25357
}
}
}
}
}
解释请求
edit使用一个解释请求提供了对分数组成部分如何计算的解释。script_score查询可以通过设置explanation参数来添加自己的解释:
GET /my-index-000001/_explain/0
{
"query": {
"script_score": {
"query": {
"match": { "message": "elasticsearch" }
},
"script": {
"source": """
long count = doc['count'].value;
double normalizedCount = count / 10;
if (explanation != null) {
explanation.set('normalized count = count / 10 = ' + count + ' / 10 = ' + normalizedCount);
}
return normalizedCount;
"""
}
}
}
}
请注意,在使用普通的 _search 请求时,explanation 将为空,因此使用条件保护是最佳实践。
包装查询
edit一个接受任何其他查询作为base64编码字符串的查询。
GET /_search
{
"query": {
"wrapper": {
"query": "eyJ0ZXJtIiA6IHsgInVzZXIuaWQiIDogImtpbWNoeSIgfX0="
}
}
}
这个查询在Spring Data Elasticsearch的上下文中更有用。它是用户在使用Spring Data仓库时可以添加自定义查询的方式。用户可以在仓库方法上添加@Query()注解。当调用这样的方法时,我们会在注解的查询参数中进行参数替换,然后将此作为搜索请求的查询部分发送。
固定查询
edit将选定的文档提升到比匹配给定查询的文档更高的排名。
此功能通常用于引导搜索者访问经过策划的文档,这些文档被提升到搜索的任何“自然”匹配之上。
提升或“固定”的文档使用存储在_id字段中的文档ID进行标识。
示例请求
editGET /_search
{
"query": {
"pinned": {
"ids": [ "1", "4", "100" ],
"organic": {
"match": {
"description": "iphone"
}
}
}
}
}
用于pinned的顶级参数
edit固定特定索引中的文档
edit如果你在多个索引中搜索,你可以使用docs在特定索引中固定一个文档:
规则查询
editrule_query 在 8.15.0 版本中被重命名为 rule。
使用 rule_query 和 ruleset_id 的旧语法已被弃用,并将在未来的版本中移除,因此强烈建议将现有的规则查询迁移到新的 API 结构。
在返回结果之前,将查询规则应用于查询。
查询规则可以用于根据匹配定义的规则以固定查询的方式提升文档,或者识别要从上下文结果集中排除的特定文档。
如果没有定义匹配的查询规则,则返回查询的“自然”匹配结果。
所有匹配的规则按照它们在查询规则集中的顺序应用。
如果同一文档同时匹配exclude规则和pinned规则,则该文档将被排除。
要使用规则查询,您首先需要一组定义的查询规则。 使用查询规则管理API来创建和管理查询规则。 有关更多信息和示例,请参阅使用查询规则进行搜索。
示例请求
editGET /_search
{
"query": {
"rule": {
"match_criteria": {
"user_query": "pugs"
},
"ruleset_ids": ["my-ruleset"],
"organic": {
"match": {
"description": "puggles"
}
}
}
}
}