建议器

编辑

使用建议器,根据提供的文本建议外观相似的术语。

resp = client.search(
    index="my-index-000001",
    query={
        "match": {
            "message": "tring out Elasticsearch"
        }
    },
    suggest={
        "my-suggestion": {
            "text": "tring out Elasticsearch",
            "term": {
                "field": "message"
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my-index-000001',
  body: {
    query: {
      match: {
        message: 'tring out Elasticsearch'
      }
    },
    suggest: {
      "my-suggestion": {
        text: 'tring out Elasticsearch',
        term: {
          field: 'message'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my-index-000001",
  query: {
    match: {
      message: "tring out Elasticsearch",
    },
  },
  suggest: {
    "my-suggestion": {
      text: "tring out Elasticsearch",
      term: {
        field: "message",
      },
    },
  },
});
console.log(response);
POST my-index-000001/_search
{
  "query" : {
    "match": {
      "message": "tring out Elasticsearch"
    }
  },
  "suggest" : {
    "my-suggestion" : {
      "text" : "tring out Elasticsearch",
      "term" : {
        "field" : "message"
      }
    }
  }
}

请求

编辑

建议功能通过使用建议器,根据提供的文本建议外观相似的术语。建议请求部分与 _search 请求中的查询部分一起定义。如果省略查询部分,则只返回建议。

示例

编辑

每个请求可以指定多个建议。每个建议都用任意名称标识。在下面的示例中,请求了两个建议。 my-suggest-1my-suggest-2 建议都使用 term 建议器,但具有不同的 text

resp = client.search(
    suggest={
        "my-suggest-1": {
            "text": "tring out Elasticsearch",
            "term": {
                "field": "message"
            }
        },
        "my-suggest-2": {
            "text": "kmichy",
            "term": {
                "field": "user.id"
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    suggest: {
      "my-suggest-1": {
        text: 'tring out Elasticsearch',
        term: {
          field: 'message'
        }
      },
      "my-suggest-2": {
        text: 'kmichy',
        term: {
          field: 'user.id'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  suggest: {
    "my-suggest-1": {
      text: "tring out Elasticsearch",
      term: {
        field: "message",
      },
    },
    "my-suggest-2": {
      text: "kmichy",
      term: {
        field: "user.id",
      },
    },
  },
});
console.log(response);
POST _search
{
  "suggest": {
    "my-suggest-1" : {
      "text" : "tring out Elasticsearch",
      "term" : {
        "field" : "message"
      }
    },
    "my-suggest-2" : {
      "text" : "kmichy",
      "term" : {
        "field" : "user.id"
      }
    }
  }
}

下面的建议响应示例包括 my-suggest-1my-suggest-2 的建议响应。每个建议部分都包含条目。每个条目实际上是建议文本中的一个标记,并包含建议条目文本、建议文本中的原始起始偏移量和长度,以及如果找到的任意数量的选项。

{
  "_shards": ...
  "hits": ...
  "took": 2,
  "timed_out": false,
  "suggest": {
    "my-suggest-1": [ {
      "text": "tring",
      "offset": 0,
      "length": 5,
      "options": [ {"text": "trying", "score": 0.8, "freq": 1 } ]
    }, {
      "text": "out",
      "offset": 6,
      "length": 3,
      "options": []
    }, {
      "text": "elasticsearch",
      "offset": 10,
      "length": 13,
      "options": []
    } ],
    "my-suggest-2": ...
  }
}

每个选项数组都包含一个选项对象,该对象包含建议的文本、其文档频率以及与建议条目文本相比的分数。分数的含义取决于所使用的建议器。词项建议器的分数基于编辑距离。

全局建议文本
编辑

为了避免重复建议文本,可以定义一个全局文本。在下面的示例中,建议文本是全局定义的,并适用于 my-suggest-1my-suggest-2 建议。

$params = [
    'body' => [
        'suggest' => [
            'text' => 'tring out Elasticsearch',
            'my-suggest-1' => [
                'term' => [
                    'field' => 'message',
                ],
            ],
            'my-suggest-2' => [
                'term' => [
                    'field' => 'user',
                ],
            ],
        ],
    ],
];
$response = $client->search($params);
resp = client.search(
    suggest={
        "text": "tring out Elasticsearch",
        "my-suggest-1": {
            "term": {
                "field": "message"
            }
        },
        "my-suggest-2": {
            "term": {
                "field": "user"
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    suggest: {
      text: 'tring out Elasticsearch',
      "my-suggest-1": {
        term: {
          field: 'message'
        }
      },
      "my-suggest-2": {
        term: {
          field: 'user'
        }
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithBody(strings.NewReader(`{
	  "suggest": {
	    "text": "tring out Elasticsearch",
	    "my-suggest-1": {
	      "term": {
	        "field": "message"
	      }
	    },
	    "my-suggest-2": {
	      "term": {
	        "field": "user"
	      }
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  suggest: {
    text: "tring out Elasticsearch",
    "my-suggest-1": {
      term: {
        field: "message",
      },
    },
    "my-suggest-2": {
      term: {
        field: "user",
      },
    },
  },
});
console.log(response);
POST _search
{
  "suggest": {
    "text" : "tring out Elasticsearch",
    "my-suggest-1" : {
      "term" : {
        "field" : "message"
      }
    },
    "my-suggest-2" : {
       "term" : {
        "field" : "user"
       }
    }
  }
}

在上面的示例中,建议文本也可以指定为特定于建议的选项。在建议级别指定的建议文本将覆盖全局级别的建议文本。

词项建议器

编辑

term 建议器根据编辑距离建议词项。提供的建议文本在建议词项之前进行分析。每个分析后的建议文本标记都提供建议的词项。term 建议器不考虑作为请求一部分的查询。

通用建议选项

编辑

text

建议文本。建议文本是必须全局或按建议设置的必需选项。

field

从中获取候选建议的字段。这是一个必需选项,需要全局或按建议设置。

analyzer

用于分析建议文本的分析器。默认为建议字段的搜索分析器。

size

每个建议文本标记返回的最大更正数。

sort

定义如何按建议文本词项对建议进行排序。两个可能的值

  • score:首先按分数排序,然后按文档频率排序,最后按词项本身排序。
  • frequency:首先按文档频率排序,然后按相似度分数排序,最后按词项本身排序。

suggest_mode

建议模式控制包含哪些建议,或者控制为哪些建议文本词项建议建议。可以指定三个可能的值

  • missing:仅为索引中不存在的建议文本词项提供建议(默认值)。
  • popular:仅建议在比原始建议文本词项更多的文档中出现的建议。
  • always:根据建议文本中的词项建议任何匹配的建议。

其他词项建议选项

编辑

max_edits

候选建议被视为建议的最大编辑距离。只能是 1 到 2 之间的值。任何其他值都会导致抛出错误请求错误。默认为 2。

prefix_length

为了成为建议的候选者,必须匹配的最小前缀字符数。默认为 1。增加此数字会提高拼写检查性能。通常,拼写错误不会出现在词项的开头。

min_word_length

为了包含在内,建议文本词项必须具有的最小长度。默认为 4

shard_size

设置从每个单独分片检索的最大建议数。在缩减阶段,仅根据 size 选项返回前 N 个建议。默认为 size 选项。将此值设置为高于 size 的值有助于以牺牲性能为代价获得更准确的拼写更正的文档频率。由于词项在分片之间进行分区,因此拼写更正的分片级文档频率可能不精确。增加此值将使这些文档频率更精确。

max_inspections

用于与 shard_size 相乘的因子,以便在分片级别检查更多的候选拼写更正。可以提高准确性,但会降低性能。默认为 5。

min_doc_freq

建议应出现在其中的文档数量的最小阈值。这可以指定为文档绝对数量或相对百分比。这可以通过仅建议高频词项来提高质量。默认为 0f,并且未启用。如果指定的值大于 1,则该数字不能是小数。此选项使用分片级文档频率。

max_term_freq

为了包含在内,建议文本标记可以存在的最大文档数量阈值。可以是相对百分比数字(例如,0.4)或表示文档频率的绝对数字。如果指定的值大于 1,则不能指定小数。默认为 0.01f。这可用于排除高频词项(通常拼写正确),以免被拼写检查。这也提高了拼写检查性能。此选项使用分片级文档频率。

string_distance

用于比较建议的词项相似程度的字符串距离实现。可以指定五个可能的值

  • internal:默认值基于 damerau_levenshtein,但经过高度优化,用于比较索引内词项的字符串距离。
  • damerau_levenshtein:基于 Damerau-Levenshtein 算法的字符串距离算法。
  • levenshtein:基于 Levenshtein 编辑距离算法的字符串距离算法。
  • jaro_winkler:基于 Jaro-Winkler 算法的字符串距离算法。
  • ngram:基于字符 n-gram 的字符串距离算法。

短语建议器

编辑

term 建议器提供了一个非常方便的 API,用于在特定字符串距离内按每个标记访问单词替代项。该 API 允许单独访问流中的每个标记,而建议选择则留给 API 使用者。但是,通常需要预先选择的建议才能呈现给最终用户。phrase 建议器在 term 建议器的基础上添加了额外的逻辑,以选择整个更正的短语,而不是基于 ngram-language 模型加权的单个标记。实际上,此建议器将能够根据共现和频率更好地决定选择哪些标记。

API 示例

编辑

通常,phrase 建议器需要预先进行特殊映射才能工作。此页面上的 phrase 建议器示例需要以下映射才能工作。reverse 分析器仅在最后一个示例中使用。

resp = client.indices.create(
    index="test",
    settings={
        "index": {
            "number_of_shards": 1,
            "analysis": {
                "analyzer": {
                    "trigram": {
                        "type": "custom",
                        "tokenizer": "standard",
                        "filter": [
                            "lowercase",
                            "shingle"
                        ]
                    },
                    "reverse": {
                        "type": "custom",
                        "tokenizer": "standard",
                        "filter": [
                            "lowercase",
                            "reverse"
                        ]
                    }
                },
                "filter": {
                    "shingle": {
                        "type": "shingle",
                        "min_shingle_size": 2,
                        "max_shingle_size": 3
                    }
                }
            }
        }
    },
    mappings={
        "properties": {
            "title": {
                "type": "text",
                "fields": {
                    "trigram": {
                        "type": "text",
                        "analyzer": "trigram"
                    },
                    "reverse": {
                        "type": "text",
                        "analyzer": "reverse"
                    }
                }
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="test",
    refresh=True,
    document={
        "title": "noble warriors"
    },
)
print(resp1)

resp2 = client.index(
    index="test",
    refresh=True,
    document={
        "title": "nobel prize"
    },
)
print(resp2)
response = client.indices.create(
  index: 'test',
  body: {
    settings: {
      index: {
        number_of_shards: 1,
        analysis: {
          analyzer: {
            trigram: {
              type: 'custom',
              tokenizer: 'standard',
              filter: [
                'lowercase',
                'shingle'
              ]
            },
            reverse: {
              type: 'custom',
              tokenizer: 'standard',
              filter: [
                'lowercase',
                'reverse'
              ]
            }
          },
          filter: {
            shingle: {
              type: 'shingle',
              min_shingle_size: 2,
              max_shingle_size: 3
            }
          }
        }
      }
    },
    mappings: {
      properties: {
        title: {
          type: 'text',
          fields: {
            trigram: {
              type: 'text',
              analyzer: 'trigram'
            },
            reverse: {
              type: 'text',
              analyzer: 'reverse'
            }
          }
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'test',
  refresh: true,
  body: {
    title: 'noble warriors'
  }
)
puts response

response = client.index(
  index: 'test',
  refresh: true,
  body: {
    title: 'nobel prize'
  }
)
puts response
const response = await client.indices.create({
  index: "test",
  settings: {
    index: {
      number_of_shards: 1,
      analysis: {
        analyzer: {
          trigram: {
            type: "custom",
            tokenizer: "standard",
            filter: ["lowercase", "shingle"],
          },
          reverse: {
            type: "custom",
            tokenizer: "standard",
            filter: ["lowercase", "reverse"],
          },
        },
        filter: {
          shingle: {
            type: "shingle",
            min_shingle_size: 2,
            max_shingle_size: 3,
          },
        },
      },
    },
  },
  mappings: {
    properties: {
      title: {
        type: "text",
        fields: {
          trigram: {
            type: "text",
            analyzer: "trigram",
          },
          reverse: {
            type: "text",
            analyzer: "reverse",
          },
        },
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "test",
  refresh: "true",
  document: {
    title: "noble warriors",
  },
});
console.log(response1);

const response2 = await client.index({
  index: "test",
  refresh: "true",
  document: {
    title: "nobel prize",
  },
});
console.log(response2);
PUT test
{
  "settings": {
    "index": {
      "number_of_shards": 1,
      "analysis": {
        "analyzer": {
          "trigram": {
            "type": "custom",
            "tokenizer": "standard",
            "filter": ["lowercase","shingle"]
          },
          "reverse": {
            "type": "custom",
            "tokenizer": "standard",
            "filter": ["lowercase","reverse"]
          }
        },
        "filter": {
          "shingle": {
            "type": "shingle",
            "min_shingle_size": 2,
            "max_shingle_size": 3
          }
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "trigram": {
            "type": "text",
            "analyzer": "trigram"
          },
          "reverse": {
            "type": "text",
            "analyzer": "reverse"
          }
        }
      }
    }
  }
}
POST test/_doc?refresh=true
{"title": "noble warriors"}
POST test/_doc?refresh=true
{"title": "nobel prize"}

设置好分析器和映射后,可以在使用 term 建议器的相同位置使用 phrase 建议器

resp = client.search(
    index="test",
    suggest={
        "text": "noble prize",
        "simple_phrase": {
            "phrase": {
                "field": "title.trigram",
                "size": 1,
                "gram_size": 3,
                "direct_generator": [
                    {
                        "field": "title.trigram",
                        "suggest_mode": "always"
                    }
                ],
                "highlight": {
                    "pre_tag": "<em>",
                    "post_tag": "</em>"
                }
            }
        }
    },
)
print(resp)
const response = await client.search({
  index: "test",
  suggest: {
    text: "noble prize",
    simple_phrase: {
      phrase: {
        field: "title.trigram",
        size: 1,
        gram_size: 3,
        direct_generator: [
          {
            field: "title.trigram",
            suggest_mode: "always",
          },
        ],
        highlight: {
          pre_tag: "<em>",
          post_tag: "</em>",
        },
      },
    },
  },
});
console.log(response);
POST test/_search
{
  "suggest": {
    "text": "noble prize",
    "simple_phrase": {
      "phrase": {
        "field": "title.trigram",
        "size": 1,
        "gram_size": 3,
        "direct_generator": [ {
          "field": "title.trigram",
          "suggest_mode": "always"
        } ],
        "highlight": {
          "pre_tag": "<em>",
          "post_tag": "</em>"
        }
      }
    }
  }
}

该响应包含按最可能的拼写更正分数排序的建议。在这种情况下,我们收到了预期的更正“诺贝尔奖”。

{
  "_shards": ...
  "hits": ...
  "timed_out": false,
  "took": 3,
  "suggest": {
    "simple_phrase" : [
      {
        "text" : "noble prize",
        "offset" : 0,
        "length" : 11,
        "options" : [ {
          "text" : "nobel prize",
          "highlighted": "<em>nobel</em> prize",
          "score" : 0.48614594
        }]
      }
    ]
  }
}

基本短语建议 API 参数

编辑

field

用于对语言模型进行 n-gram 查找的字段的名称,建议器将使用此字段来获取统计信息以对更正进行评分。此字段是强制性的。

gram_size

设置 field 中 n-gram(shingles)的最大大小。如果字段不包含 n-gram(shingles),则应省略此项或设置为 1。请注意,Elasticsearch 尝试基于指定的 field 检测 gram 大小。如果字段使用 shingle 过滤器,则 gram_size 设置为 max_shingle_size(如果未显式设置)。

real_word_error_likelihood

即使该词项存在于字典中,该词项拼写错误的概率。默认值为 0.95,这意味着 5% 的实词拼写错误。

confidence

置信度级别定义一个应用于输入短语分数的因子,该因子用作其他建议候选者的阈值。只有得分高于阈值的候选者才会包含在结果中。例如,置信度级别为 1.0 将仅返回得分高于输入短语的建议。如果设置为 0.0,则返回前 N 个候选者。默认值为 1.0

max_errors

为了形成更正,被视为拼写错误的词项的最大百分比。此方法接受范围 [0..1) 内的浮点值作为实际查询词项的分数,或者接受 >=1 的数字作为查询词项的绝对数量。默认值设置为 1.0,这意味着仅返回最多一个拼写错误的词项的更正。请注意,将此值设置得过高可能会对性能产生负面影响。建议使用 12 等较低的值;否则,在建议调用中花费的时间可能会超过在查询执行中花费的时间。

separator

用于分隔双字母组字段中词项的分隔符。如果未设置,则将空格字符用作分隔符。

size

为每个单独的查询词项生成的候选者数量。像 35 这样的低数字通常会产生良好的结果。增加此值可以引入编辑距离更大的词项。默认值为 5

analyzer

设置用于分析建议文本的分析器。默认为通过 field 传递的建议字段的搜索分析器。

shard_size

设置从每个单独分片检索的最大建议词项数。在缩减阶段,仅根据 size 选项返回前 N 个建议。默认为 5

text

设置要为其提供建议的文本/查询。

highlight

设置建议高亮显示。如果未提供,则不返回 highlighted 字段。如果提供,则必须精确包含 pre_tagpost_tag,它们会包裹更改过的标记。如果连续更改了多个标记,则会包裹整个更改过的标记短语,而不是每个标记。

collate

针对指定的 query 检查每个建议,以修剪索引中不存在匹配文档的建议。建议的 collate 查询仅在生成建议的本地分片上运行。query 必须指定,并且可以是模板化的。请参阅 搜索模板。当前建议会自动作为 {{suggestion}} 变量提供,应在查询中使用。您仍然可以指定自己的模板 params - suggestion 值将被添加到您指定的变量中。此外,您可以指定一个 prune 来控制是否返回所有短语建议;当设置为 true 时,建议将有一个额外的选项 collate_match,如果找到短语的匹配文档,则该选项为 true,否则为 falseprune 的默认值为 false

resp = client.search(
    index="test",
    suggest={
        "text": "noble prize",
        "simple_phrase": {
            "phrase": {
                "field": "title.trigram",
                "size": 1,
                "direct_generator": [
                    {
                        "field": "title.trigram",
                        "suggest_mode": "always",
                        "min_word_length": 1
                    }
                ],
                "collate": {
                    "query": {
                        "source": {
                            "match": {
                                "{{field_name}}": "{{suggestion}}"
                            }
                        }
                    },
                    "params": {
                        "field_name": "title"
                    },
                    "prune": True
                }
            }
        }
    },
)
print(resp)
const response = await client.search({
  index: "test",
  suggest: {
    text: "noble prize",
    simple_phrase: {
      phrase: {
        field: "title.trigram",
        size: 1,
        direct_generator: [
          {
            field: "title.trigram",
            suggest_mode: "always",
            min_word_length: 1,
          },
        ],
        collate: {
          query: {
            source: {
              match: {
                "{{field_name}}": "{{suggestion}}",
              },
            },
          },
          params: {
            field_name: "title",
          },
          prune: true,
        },
      },
    },
  },
});
console.log(response);
POST test/_search
{
  "suggest": {
    "text" : "noble prize",
    "simple_phrase" : {
      "phrase" : {
        "field" :  "title.trigram",
        "size" :   1,
        "direct_generator" : [ {
          "field" :            "title.trigram",
          "suggest_mode" :     "always",
          "min_word_length" :  1
        } ],
        "collate": {
          "query": { 
            "source" : {
              "match": {
                "{{field_name}}" : "{{suggestion}}" 
              }
            }
          },
          "params": {"field_name" : "title"}, 
          "prune": true 
        }
      }
    }
  }
}

此查询将为每个建议运行一次。

{{suggestion}} 变量将被每个建议的文本替换。

params 中指定了一个额外的 field_name 变量,并由 match 查询使用。

所有建议都将返回一个额外的 collate_match 选项,指示生成的短语是否匹配任何文档。

平滑模型

编辑

phrase 建议器支持多种平滑模型,以平衡不频繁的 grams(索引中不存在的 grams(shingles))和频繁的 grams(在索引中至少出现一次)之间的权重。可以通过将 smoothing 参数设置为以下选项之一来选择平滑模型。每个平滑模型都支持可以配置的特定属性。

stupid_backoff

一个简单的回退模型,如果较高阶 n-gram 模型的计数为 0,则回退到较低阶 n-gram 模型,并以一个常数因子折扣较低阶 n-gram 模型。默认的 discount0.4。Stupid Backoff 是默认模型。

laplace

一个使用加性平滑的平滑模型,其中将一个常数(通常为 1.0 或更小)添加到所有计数中以平衡权重。默认的 alpha0.5

linear_interpolation

一个平滑模型,它根据用户提供的权重(lambdas)取 unigrams、bigrams 和 trigrams 的加权平均值。线性插值没有任何默认值。必须提供所有参数(trigram_lambdabigram_lambdaunigram_lambda)。

resp = client.search(
    index="test",
    suggest={
        "text": "obel prize",
        "simple_phrase": {
            "phrase": {
                "field": "title.trigram",
                "size": 1,
                "smoothing": {
                    "laplace": {
                        "alpha": 0.7
                    }
                }
            }
        }
    },
)
print(resp)
const response = await client.search({
  index: "test",
  suggest: {
    text: "obel prize",
    simple_phrase: {
      phrase: {
        field: "title.trigram",
        size: 1,
        smoothing: {
          laplace: {
            alpha: 0.7,
          },
        },
      },
    },
  },
});
console.log(response);
POST test/_search
{
  "suggest": {
    "text" : "obel prize",
    "simple_phrase" : {
      "phrase" : {
        "field" : "title.trigram",
        "size" : 1,
        "smoothing" : {
          "laplace" : {
            "alpha" : 0.7
          }
        }
      }
    }
  }
}

候选生成器

编辑

phrase 建议器使用候选生成器为给定文本中的每个术语生成可能的术语列表。单个候选生成器类似于为文本中的每个单独的术语调用的 term 建议器。生成器的输出随后与来自其他术语的候选组合在一起,以进行建议候选评分。

目前仅支持一种候选生成器类型,即 direct_generator。Phrase suggest API 接受键 direct_generator 下的生成器列表;列表中的每个生成器都针对原始文本中的每个术语调用。

直接生成器

编辑

直接生成器支持以下参数

field

从中获取候选建议的字段。这是一个必需选项,需要全局或按建议设置。

size

每个建议文本标记返回的最大更正数。

suggest_mode

suggest 模式控制在每个分片上生成的建议中包含哪些建议。除了 always 之外的所有值都可以被认为是优化,以生成更少的建议在每个分片上进行测试,并且在组合在每个分片上生成的建议时不会重新检查。因此,即使其他分片包含它们,missing 也会为不包含术语的分片上的术语生成建议。这些应该使用 confidence 过滤掉。可以指定三个可能的值

  • missing:仅为分片中不存在的术语生成建议。这是默认值。
  • popular:仅建议在分片上比原始术语出现在更多文档中的术语。
  • always:根据建议文本中的词项建议任何匹配的建议。

max_edits

候选建议被视为建议的最大编辑距离。只能是 1 到 2 之间的值。任何其他值都会导致抛出错误请求错误。默认为 2。

prefix_length

为了成为候选建议而必须匹配的最小前缀字符数。默认为 1。增加此数字可提高拼写检查性能。通常,拼写错误不会出现在术语的开头。

min_word_length

为了包含在内,建议文本术语必须具有的最小长度。默认为 4。

max_inspections

用于与 shard_size 相乘的因子,以便在分片级别检查更多的候选拼写更正。可以提高准确性,但会降低性能。默认为 5。

min_doc_freq

建议应出现在其中的文档数量的最小阈值。这可以指定为文档绝对数量或相对百分比。这可以通过仅建议高频词项来提高质量。默认为 0f,并且未启用。如果指定的值大于 1,则该数字不能是小数。此选项使用分片级文档频率。

max_term_freq

为了包含在内,建议文本标记可以存在的最大文档数量阈值。可以是相对百分比数字(例如,0.4)或表示文档频率的绝对数字。如果指定的值大于 1,则不能指定小数。默认为 0.01f。这可用于排除高频词项(通常拼写正确),以免被拼写检查。这也提高了拼写检查性能。此选项使用分片级文档频率。

pre_filter

应用于传递给此候选生成器的每个标记的过滤器(分析器)。在生成候选之前,此过滤器将应用于原始标记。

post_filter

应用于每个生成的标记(在它们传递给实际短语评分器之前)的过滤器(分析器)。

以下示例显示了带有两个生成器的 phrase 建议调用:第一个使用包含普通索引术语的字段,第二个使用使用 reverse 过滤器(标记以相反的顺序索引)索引术语的字段。这用于克服直接生成器需要恒定前缀以提供高性能建议的限制。pre_filterpost_filter 选项接受普通的分析器名称。

resp = client.search(
    index="test",
    suggest={
        "text": "obel prize",
        "simple_phrase": {
            "phrase": {
                "field": "title.trigram",
                "size": 1,
                "direct_generator": [
                    {
                        "field": "title.trigram",
                        "suggest_mode": "always"
                    },
                    {
                        "field": "title.reverse",
                        "suggest_mode": "always",
                        "pre_filter": "reverse",
                        "post_filter": "reverse"
                    }
                ]
            }
        }
    },
)
print(resp)
const response = await client.search({
  index: "test",
  suggest: {
    text: "obel prize",
    simple_phrase: {
      phrase: {
        field: "title.trigram",
        size: 1,
        direct_generator: [
          {
            field: "title.trigram",
            suggest_mode: "always",
          },
          {
            field: "title.reverse",
            suggest_mode: "always",
            pre_filter: "reverse",
            post_filter: "reverse",
          },
        ],
      },
    },
  },
});
console.log(response);
POST test/_search
{
  "suggest": {
    "text" : "obel prize",
    "simple_phrase" : {
      "phrase" : {
        "field" : "title.trigram",
        "size" : 1,
        "direct_generator" : [ {
          "field" : "title.trigram",
          "suggest_mode" : "always"
        }, {
          "field" : "title.reverse",
          "suggest_mode" : "always",
          "pre_filter" : "reverse",
          "post_filter" : "reverse"
        } ]
      }
    }
  }
}

pre_filterpost_filter 还可用于在生成候选后注入同义词。例如,对于查询 captain usq,我们可能会为术语 usq 生成候选 usa,这是 america 的同义词。如果此短语得分足够高,这使我们能够向用户展示 captain america

Completion 建议器

编辑

completion 建议器提供自动完成/边输入边搜索功能。这是一种导航功能,可以在用户输入时引导用户找到相关结果,从而提高搜索精度。它不适用于拼写校正或“您是不是要找”功能,例如 termphrase 建议器。

理想情况下,自动完成功能应该与用户键入的速度一样快,以便提供与用户已键入内容相关的即时反馈。因此,completion 建议器针对速度进行了优化。该建议器使用可以快速查找的数据结构,但是构建成本很高并且存储在内存中。

映射

编辑

要使用 completion 建议器,请将您要从中生成建议的字段映射为 completion 类型。这将索引该字段值以进行快速完成。

resp = client.indices.create(
    index="music",
    mappings={
        "properties": {
            "suggest": {
                "type": "completion"
            }
        }
    },
)
print(resp)
response = client.indices.create(
  index: 'music',
  body: {
    mappings: {
      properties: {
        suggest: {
          type: 'completion'
        }
      }
    }
  }
)
puts response
const response = await client.indices.create({
  index: "music",
  mappings: {
    properties: {
      suggest: {
        type: "completion",
      },
    },
  },
});
console.log(response);
PUT music
{
  "mappings": {
    "properties": {
      "suggest": {
        "type": "completion"
      }
    }
  }
}

completion 字段的参数

编辑

completion 字段接受以下参数

analyzer

要使用的索引分析器,默认为 simple

search_analyzer

要使用的搜索分析器,默认为 analyzer 的值。

preserve_separators

保留分隔符,默认为 true。如果禁用此选项,如果您建议 foof,则可能会找到以 Foo Fighters 开头的字段。

preserve_position_increments

启用位置增量,默认为 true。如果禁用此选项并使用停用词分析器,如果您建议 b,则可能会获得以 The Beatles 开头的字段。注意:如果您能够丰富您的数据,您还可以通过索引两个输入,BeatlesThe Beatles 来实现此目的,无需更改简单的分析器。

max_input_length

限制单个输入的长度,默认为 50 个 UTF-16 代码点。此限制仅在索引时使用,以减少每个输入字符串的字符总数,从而防止大量输入使底层数据结构膨胀。大多数用例不会受到默认值的影响,因为前缀完成很少会增长到超过少数几个字符的前缀。

索引

编辑

您可以像索引任何其他字段一样索引建议。一个建议由一个 input 和一个可选的 weight 属性组成。input 是建议查询期望匹配的文本,而 weight 决定建议的评分方式。索引建议如下

resp = client.index(
    index="music",
    id="1",
    refresh=True,
    document={
        "suggest": {
            "input": [
                "Nevermind",
                "Nirvana"
            ],
            "weight": 34
        }
    },
)
print(resp)
response = client.index(
  index: 'music',
  id: 1,
  refresh: true,
  body: {
    suggest: {
      input: [
        'Nevermind',
        'Nirvana'
      ],
      weight: 34
    }
  }
)
puts response
const response = await client.index({
  index: "music",
  id: 1,
  refresh: "true",
  document: {
    suggest: {
      input: ["Nevermind", "Nirvana"],
      weight: 34,
    },
  },
});
console.log(response);
PUT music/_doc/1?refresh
{
  "suggest" : {
    "input": [ "Nevermind", "Nirvana" ],
    "weight" : 34
  }
}

支持以下参数

input

要存储的输入,可以是字符串数组,也可以只是一个字符串。此字段为必填项。

此值不能包含以下 UTF-16 控制字符

  • \u0000 (null)
  • \u001f (信息分隔符一)
  • \u001e (信息分隔符二)

weight

一个正整数或一个包含正整数的字符串,定义权重并允许您对建议进行排名。此字段为可选字段。

您可以为文档索引多个建议,如下所示

resp = client.index(
    index="music",
    id="1",
    refresh=True,
    document={
        "suggest": [
            {
                "input": "Nevermind",
                "weight": 10
            },
            {
                "input": "Nirvana",
                "weight": 3
            }
        ]
    },
)
print(resp)
response = client.index(
  index: 'music',
  id: 1,
  refresh: true,
  body: {
    suggest: [
      {
        input: 'Nevermind',
        weight: 10
      },
      {
        input: 'Nirvana',
        weight: 3
      }
    ]
  }
)
puts response
const response = await client.index({
  index: "music",
  id: 1,
  refresh: "true",
  document: {
    suggest: [
      {
        input: "Nevermind",
        weight: 10,
      },
      {
        input: "Nirvana",
        weight: 3,
      },
    ],
  },
});
console.log(response);
PUT music/_doc/1?refresh
{
  "suggest": [
    {
      "input": "Nevermind",
      "weight": 10
    },
    {
      "input": "Nirvana",
      "weight": 3
    }
  ]
}

您可以使用以下简写形式。请注意,您不能使用简写形式指定建议的权重。

resp = client.index(
    index="music",
    id="1",
    refresh=True,
    document={
        "suggest": [
            "Nevermind",
            "Nirvana"
        ]
    },
)
print(resp)
response = client.index(
  index: 'music',
  id: 1,
  refresh: true,
  body: {
    suggest: [
      'Nevermind',
      'Nirvana'
    ]
  }
)
puts response
const response = await client.index({
  index: "music",
  id: 1,
  refresh: "true",
  document: {
    suggest: ["Nevermind", "Nirvana"],
  },
});
console.log(response);
PUT music/_doc/1?refresh
{
  "suggest" : [ "Nevermind", "Nirvana" ]
}

查询

编辑

建议的工作方式与往常相同,除了您必须将建议类型指定为 completion。建议是近实时的,这意味着可以通过 refresh 使新的建议可见,并且一旦删除的文档将永远不会显示。此请求

resp = client.search(
    index="music",
    pretty=True,
    suggest={
        "song-suggest": {
            "prefix": "nir",
            "completion": {
                "field": "suggest"
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'music',
  pretty: true,
  body: {
    suggest: {
      "song-suggest": {
        prefix: 'nir',
        completion: {
          field: 'suggest'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "music",
  pretty: "true",
  suggest: {
    "song-suggest": {
      prefix: "nir",
      completion: {
        field: "suggest",
      },
    },
  },
});
console.log(response);
POST music/_search?pretty
{
  "suggest": {
    "song-suggest": {
      "prefix": "nir",        
      "completion": {         
          "field": "suggest"  
      }
    }
  }
}

用于搜索建议的前缀

建议的类型

要在其中搜索建议的字段的名称

返回此响应

{
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits": ...
  "took": 2,
  "timed_out": false,
  "suggest": {
    "song-suggest" : [ {
      "text" : "nir",
      "offset" : 0,
      "length" : 3,
      "options" : [ {
        "text" : "Nirvana",
        "_index": "music",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "suggest": ["Nevermind", "Nirvana"]
        }
      } ]
    } ]
  }
}

必须启用 _source 元数据字段,这是默认行为,以启用使用建议返回 _source

配置的建议权重以 _score 的形式返回。text 字段使用已索引建议的 input。 默认情况下,建议会返回完整的文档 _source_source 的大小会因磁盘读取和网络传输开销而影响性能。 为了节省一些网络开销,请使用源过滤,从 _source 中过滤掉不必要的字段,以最小化 _source 的大小。 请注意,_suggest 端点不支持源过滤,但在 _search 端点上使用 suggest 是支持的。

resp = client.search(
    index="music",
    source="suggest",
    suggest={
        "song-suggest": {
            "prefix": "nir",
            "completion": {
                "field": "suggest",
                "size": 5
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'music',
  body: {
    _source: 'suggest',
    suggest: {
      "song-suggest": {
        prefix: 'nir',
        completion: {
          field: 'suggest',
          size: 5
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "music",
  _source: "suggest",
  suggest: {
    "song-suggest": {
      prefix: "nir",
      completion: {
        field: "suggest",
        size: 5,
      },
    },
  },
});
console.log(response);
POST music/_search
{
  "_source": "suggest",     
  "suggest": {
    "song-suggest": {
      "prefix": "nir",
      "completion": {
        "field": "suggest", 
        "size": 5           
      }
    }
  }
}

过滤源,使其仅返回 suggest 字段

要在其中搜索建议的字段的名称

要返回的建议数量

应该类似于

{
  "took": 6,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 0,
      "relation": "eq"
    },
    "max_score": null,
    "hits": []
  },
  "suggest": {
    "song-suggest": [ {
        "text": "nir",
        "offset": 0,
        "length": 3,
        "options": [ {
            "text": "Nirvana",
            "_index": "music",
            "_id": "1",
            "_score": 1.0,
            "_source": {
              "suggest": [ "Nevermind", "Nirvana" ]
            }
          } ]
      } ]
  }
}

基本的完成建议器查询支持以下参数

field

要在其上运行查询的字段名称(必需)。

size

要返回的建议数量(默认为 5)。

skip_duplicates

是否应过滤掉重复的建议(默认为 false)。

完成建议器会考虑索引中的所有文档。有关如何查询文档子集的说明,请参阅上下文建议器

如果完成查询跨越多个分片,建议将分两个阶段执行,最后一个阶段从分片中获取相关文档,这意味着针对单个分片执行完成请求的性能更高,因为当建议跨越多个分片时,会产生文档获取开销。为了获得最佳的完成性能,建议将完成项索引到单个分片索引中。如果由于分片大小而导致堆使用率过高,仍然建议将索引分成多个分片,而不是优化完成性能。

跳过重复建议

编辑

查询可能会返回来自不同文档的重复建议。可以通过将 skip_duplicates 设置为 true 来修改此行为。设置后,此选项会从结果中过滤掉具有重复建议的文档。

resp = client.search(
    index="music",
    pretty=True,
    suggest={
        "song-suggest": {
            "prefix": "nor",
            "completion": {
                "field": "suggest",
                "skip_duplicates": True
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'music',
  pretty: true,
  body: {
    suggest: {
      "song-suggest": {
        prefix: 'nor',
        completion: {
          field: 'suggest',
          skip_duplicates: true
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "music",
  pretty: "true",
  suggest: {
    "song-suggest": {
      prefix: "nor",
      completion: {
        field: "suggest",
        skip_duplicates: true,
      },
    },
  },
});
console.log(response);
POST music/_search?pretty
{
  "suggest": {
    "song-suggest": {
      "prefix": "nor",
      "completion": {
        "field": "suggest",
        "skip_duplicates": true
      }
    }
  }
}

当设置为 true 时,此选项可能会降低搜索速度,因为需要访问更多建议才能找到前 N 个。

模糊查询

编辑

完成建议器还支持模糊查询 — 这意味着您的搜索中可能存在拼写错误,但仍然可以获得结果。

resp = client.search(
    index="music",
    pretty=True,
    suggest={
        "song-suggest": {
            "prefix": "nor",
            "completion": {
                "field": "suggest",
                "fuzzy": {
                    "fuzziness": 2
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'music',
  pretty: true,
  body: {
    suggest: {
      "song-suggest": {
        prefix: 'nor',
        completion: {
          field: 'suggest',
          fuzzy: {
            fuzziness: 2
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "music",
  pretty: "true",
  suggest: {
    "song-suggest": {
      prefix: "nor",
      completion: {
        field: "suggest",
        fuzzy: {
          fuzziness: 2,
        },
      },
    },
  },
});
console.log(response);
POST music/_search?pretty
{
  "suggest": {
    "song-suggest": {
      "prefix": "nor",
      "completion": {
        "field": "suggest",
        "fuzzy": {
          "fuzziness": 2
        }
      }
    }
  }
}

与查询 prefix 共享最长前缀的建议将获得更高的评分。

模糊查询可以接受特定的模糊参数。支持以下参数

fuzziness

模糊因子,默认为 AUTO。有关允许的设置,请参阅模糊度

transpositions

如果设置为 true,则换位将被视为一个更改而不是两个更改,默认为 true

min_length

返回模糊建议之前输入的最小长度,默认为 3

prefix_length

不检查模糊替代方案的输入的最小长度,默认为 1

unicode_aware

如果 true,所有度量(例如模糊编辑距离、换位和长度)都以 Unicode 代码点而不是字节来度量。这比原始字节稍慢,因此默认设置为 false

如果您想坚持使用默认值,但仍然使用模糊查询,您可以使用 fuzzy: {}fuzzy: true

正则表达式查询

编辑

完成建议器还支持正则表达式查询,这意味着您可以将前缀表示为正则表达式

resp = client.search(
    index="music",
    pretty=True,
    suggest={
        "song-suggest": {
            "regex": "n[ever|i]r",
            "completion": {
                "field": "suggest"
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'music',
  pretty: true,
  body: {
    suggest: {
      "song-suggest": {
        regex: 'n[ever|i]r',
        completion: {
          field: 'suggest'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "music",
  pretty: "true",
  suggest: {
    "song-suggest": {
      regex: "n[ever|i]r",
      completion: {
        field: "suggest",
      },
    },
  },
});
console.log(response);
POST music/_search?pretty
{
  "suggest": {
    "song-suggest": {
      "regex": "n[ever|i]r",
      "completion": {
        "field": "suggest"
      }
    }
  }
}

正则表达式查询可以接受特定的正则表达式参数。支持以下参数

flags

可能的标志包括 ALL(默认)、ANYSTRINGCOMPLEMENTEMPTYINTERSECTIONINTERVALNONE。有关其含义,请参阅regexp-syntax

max_determinized_states

正则表达式很危险,因为很容易意外地创建一个看似无害的正则表达式,该正则表达式需要 Lucene 执行指数级的内部确定性自动机状态(以及相应的 RAM 和 CPU)。Lucene 使用 max_determinized_states 设置(默认为 10000)来防止这种情况。您可以提高此限制以允许执行更复杂的正则表达式。

上下文建议器

编辑

完成建议器会考虑索引中的所有文档,但通常需要提供按某些条件过滤和/或提升的建议。例如,您希望按某些艺术家过滤歌曲标题,或者您希望根据歌曲的类型来提升歌曲标题。

为了实现建议过滤和/或提升,您可以在配置完成字段时添加上下文映射。您可以为一个完成字段定义多个上下文映射。每个上下文映射都有一个唯一的名称和一个类型。有两种类型:categorygeo。上下文映射在字段映射中的 contexts 参数下配置。

在索引和查询启用上下文的完成字段时,必须提供上下文。

允许的最大完成字段上下文映射数为 10。

以下定义了类型,每种类型都为完成字段提供了两个上下文映射

resp = client.indices.create(
    index="place",
    mappings={
        "properties": {
            "suggest": {
                "type": "completion",
                "contexts": [
                    {
                        "name": "place_type",
                        "type": "category"
                    },
                    {
                        "name": "location",
                        "type": "geo",
                        "precision": 4
                    }
                ]
            }
        }
    },
)
print(resp)

resp1 = client.indices.create(
    index="place_path_category",
    mappings={
        "properties": {
            "suggest": {
                "type": "completion",
                "contexts": [
                    {
                        "name": "place_type",
                        "type": "category",
                        "path": "cat"
                    },
                    {
                        "name": "location",
                        "type": "geo",
                        "precision": 4,
                        "path": "loc"
                    }
                ]
            },
            "loc": {
                "type": "geo_point"
            }
        }
    },
)
print(resp1)
response = client.indices.create(
  index: 'place',
  body: {
    mappings: {
      properties: {
        suggest: {
          type: 'completion',
          contexts: [
            {
              name: 'place_type',
              type: 'category'
            },
            {
              name: 'location',
              type: 'geo',
              precision: 4
            }
          ]
        }
      }
    }
  }
)
puts response

response = client.indices.create(
  index: 'place_path_category',
  body: {
    mappings: {
      properties: {
        suggest: {
          type: 'completion',
          contexts: [
            {
              name: 'place_type',
              type: 'category',
              path: 'cat'
            },
            {
              name: 'location',
              type: 'geo',
              precision: 4,
              path: 'loc'
            }
          ]
        },
        loc: {
          type: 'geo_point'
        }
      }
    }
  }
)
puts response
const response = await client.indices.create({
  index: "place",
  mappings: {
    properties: {
      suggest: {
        type: "completion",
        contexts: [
          {
            name: "place_type",
            type: "category",
          },
          {
            name: "location",
            type: "geo",
            precision: 4,
          },
        ],
      },
    },
  },
});
console.log(response);

const response1 = await client.indices.create({
  index: "place_path_category",
  mappings: {
    properties: {
      suggest: {
        type: "completion",
        contexts: [
          {
            name: "place_type",
            type: "category",
            path: "cat",
          },
          {
            name: "location",
            type: "geo",
            precision: 4,
            path: "loc",
          },
        ],
      },
      loc: {
        type: "geo_point",
      },
    },
  },
});
console.log(response1);
PUT place
{
  "mappings": {
    "properties": {
      "suggest": {
        "type": "completion",
        "contexts": [
          {                                 
            "name": "place_type",
            "type": "category"
          },
          {                                 
            "name": "location",
            "type": "geo",
            "precision": 4
          }
        ]
      }
    }
  }
}
PUT place_path_category
{
  "mappings": {
    "properties": {
      "suggest": {
        "type": "completion",
        "contexts": [
          {                           
            "name": "place_type",
            "type": "category",
            "path": "cat"
          },
          {                           
            "name": "location",
            "type": "geo",
            "precision": 4,
            "path": "loc"
          }
        ]
      },
      "loc": {
        "type": "geo_point"
      }
    }
  }
}

定义一个名为 place_typecategory 上下文,其中类别必须与建议一起发送。

定义一个名为 locationgeo 上下文,其中类别必须与建议一起发送。

定义一个名为 place_typecategory 上下文,其中类别是从 cat 字段读取的。

定义一个名为 locationgeo 上下文,其中类别是从 loc 字段读取的。

添加上下文映射会增加完成字段的索引大小。完成索引完全驻留在堆中,您可以使用索引统计信息来监视完成字段索引大小。

类别上下文
编辑

category 上下文允许您在索引时将一个或多个类别与建议相关联。在查询时,可以通过其关联的类别来过滤和提升建议。

映射的设置方式类似于上面的 place_type 字段。如果定义了 path,则类别将从文档中的该路径读取,否则它们必须像这样在 suggest 字段中发送

resp = client.index(
    index="place",
    id="1",
    document={
        "suggest": {
            "input": [
                "timmy's",
                "starbucks",
                "dunkin donuts"
            ],
            "contexts": {
                "place_type": [
                    "cafe",
                    "food"
                ]
            }
        }
    },
)
print(resp)
response = client.index(
  index: 'place',
  id: 1,
  body: {
    suggest: {
      input: [
        "timmy's",
        'starbucks',
        'dunkin donuts'
      ],
      contexts: {
        place_type: [
          'cafe',
          'food'
        ]
      }
    }
  }
)
puts response
const response = await client.index({
  index: "place",
  id: 1,
  document: {
    suggest: {
      input: ["timmy's", "starbucks", "dunkin donuts"],
      contexts: {
        place_type: ["cafe", "food"],
      },
    },
  },
});
console.log(response);
PUT place/_doc/1
{
  "suggest": {
    "input": [ "timmy's", "starbucks", "dunkin donuts" ],
    "contexts": {
      "place_type": [ "cafe", "food" ]                    
    }
  }
}

这些建议将与 cafefood 类别关联。

如果映射具有 path,则以下索引请求足以添加类别

resp = client.index(
    index="place_path_category",
    id="1",
    document={
        "suggest": [
            "timmy's",
            "starbucks",
            "dunkin donuts"
        ],
        "cat": [
            "cafe",
            "food"
        ]
    },
)
print(resp)
response = client.index(
  index: 'place_path_category',
  id: 1,
  body: {
    suggest: [
      "timmy's",
      'starbucks',
      'dunkin donuts'
    ],
    cat: [
      'cafe',
      'food'
    ]
  }
)
puts response
const response = await client.index({
  index: "place_path_category",
  id: 1,
  document: {
    suggest: ["timmy's", "starbucks", "dunkin donuts"],
    cat: ["cafe", "food"],
  },
});
console.log(response);
PUT place_path_category/_doc/1
{
  "suggest": ["timmy's", "starbucks", "dunkin donuts"],
  "cat": ["cafe", "food"] 
}

这些建议将与 cafefood 类别关联。

如果上下文映射引用另一个字段并且类别已显式索引,则建议将使用两组类别进行索引。

类别查询
编辑

可以按一个或多个类别过滤建议。以下按多个类别过滤建议

resp = client.search(
    index="place",
    pretty=True,
    suggest={
        "place_suggestion": {
            "prefix": "tim",
            "completion": {
                "field": "suggest",
                "size": 10,
                "contexts": {
                    "place_type": [
                        "cafe",
                        "restaurants"
                    ]
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'place',
  pretty: true,
  body: {
    suggest: {
      place_suggestion: {
        prefix: 'tim',
        completion: {
          field: 'suggest',
          size: 10,
          contexts: {
            place_type: [
              'cafe',
              'restaurants'
            ]
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "place",
  pretty: "true",
  suggest: {
    place_suggestion: {
      prefix: "tim",
      completion: {
        field: "suggest",
        size: 10,
        contexts: {
          place_type: ["cafe", "restaurants"],
        },
      },
    },
  },
});
console.log(response);
POST place/_search?pretty
{
  "suggest": {
    "place_suggestion": {
      "prefix": "tim",
      "completion": {
        "field": "suggest",
        "size": 10,
        "contexts": {
          "place_type": [ "cafe", "restaurants" ]
        }
      }
    }
  }
}

如果在查询中设置了多个类别或类别上下文,它们将合并为析取。这意味着如果建议包含至少一个提供的上下文值,则会匹配。

具有某些类别的建议可以比其他建议得到更高的提升。以下按类别过滤建议,并另外提升与某些类别关联的建议

resp = client.search(
    index="place",
    pretty=True,
    suggest={
        "place_suggestion": {
            "prefix": "tim",
            "completion": {
                "field": "suggest",
                "size": 10,
                "contexts": {
                    "place_type": [
                        {
                            "context": "cafe"
                        },
                        {
                            "context": "restaurants",
                            "boost": 2
                        }
                    ]
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'place',
  pretty: true,
  body: {
    suggest: {
      place_suggestion: {
        prefix: 'tim',
        completion: {
          field: 'suggest',
          size: 10,
          contexts: {
            place_type: [
              {
                context: 'cafe'
              },
              {
                context: 'restaurants',
                boost: 2
              }
            ]
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "place",
  pretty: "true",
  suggest: {
    place_suggestion: {
      prefix: "tim",
      completion: {
        field: "suggest",
        size: 10,
        contexts: {
          place_type: [
            {
              context: "cafe",
            },
            {
              context: "restaurants",
              boost: 2,
            },
          ],
        },
      },
    },
  },
});
console.log(response);
POST place/_search?pretty
{
  "suggest": {
    "place_suggestion": {
      "prefix": "tim",
      "completion": {
        "field": "suggest",
        "size": 10,
        "contexts": {
          "place_type": [                             
            { "context": "cafe" },
            { "context": "restaurants", "boost": 2 }
          ]
        }
      }
    }
  }
}

上下文查询会筛选与类别 caferestaurants 关联的建议,并将与 restaurants 关联的建议的权重提高 2

除了接受类别值之外,上下文查询还可以由多个类别上下文子句组成。对于 category 上下文子句,支持以下参数

context

要过滤/提升的类别的的值。这是必需的。

boost

建议的分数应提升的因子,分数是通过将提升因子与建议权重相乘来计算的,默认为 1

prefix

是否应将类别值视为前缀。例如,如果设置为 true,您可以通过指定 type 的类别前缀来过滤 type1type2 等类别。默认为 false

如果建议条目匹配多个上下文,则最终得分将计算为任何匹配上下文产生的最大得分。

地理位置上下文
编辑

geo 上下文允许您在索引时将一个或多个地理点或地理散列与建议相关联。在查询时,如果建议在指定地理位置的某个距离内,则可以过滤和提升建议。

在内部,地理点会编码为具有指定精度的地理散列。

地理映射
编辑

除了 path 设置之外,geo 上下文映射还接受以下设置

precision

这定义了要索引的地理散列的精度,可以指定为距离值(5m10km 等),也可以指定为原始地理散列精度(1..12)。默认为 6 的原始地理散列精度值。

索引时 precision 设置设置了查询时可以使用的最大地理散列精度。

索引地理上下文
编辑

geo 上下文可以显式设置为建议,也可以通过 path 参数从文档中的地理点字段索引,类似于 category 上下文。将多个地理位置上下文与建议关联,将为每个地理位置索引该建议。以下索引包含两个地理位置上下文的建议

resp = client.index(
    index="place",
    id="1",
    document={
        "suggest": {
            "input": "timmy's",
            "contexts": {
                "location": [
                    {
                        "lat": 43.6624803,
                        "lon": -79.3863353
                    },
                    {
                        "lat": 43.6624718,
                        "lon": -79.3873227
                    }
                ]
            }
        }
    },
)
print(resp)
response = client.index(
  index: 'place',
  id: 1,
  body: {
    suggest: {
      input: "timmy's",
      contexts: {
        location: [
          {
            lat: 43.6624803,
            lon: -79.3863353
          },
          {
            lat: 43.6624718,
            lon: -79.3873227
          }
        ]
      }
    }
  }
)
puts response
const response = await client.index({
  index: "place",
  id: 1,
  document: {
    suggest: {
      input: "timmy's",
      contexts: {
        location: [
          {
            lat: 43.6624803,
            lon: -79.3863353,
          },
          {
            lat: 43.6624718,
            lon: -79.3873227,
          },
        ],
      },
    },
  },
});
console.log(response);
PUT place/_doc/1
{
  "suggest": {
    "input": "timmy's",
    "contexts": {
      "location": [
        {
          "lat": 43.6624803,
          "lon": -79.3863353
        },
        {
          "lat": 43.6624718,
          "lon": -79.3873227
        }
      ]
    }
  }
}
地理位置查询
编辑

可以根据建议与一个或多个地理点的接近程度来过滤和提升建议。以下过滤落在地理点的编码地理散列所代表区域内的建议

resp = client.search(
    index="place",
    suggest={
        "place_suggestion": {
            "prefix": "tim",
            "completion": {
                "field": "suggest",
                "size": 10,
                "contexts": {
                    "location": {
                        "lat": 43.662,
                        "lon": -79.38
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'place',
  body: {
    suggest: {
      place_suggestion: {
        prefix: 'tim',
        completion: {
          field: 'suggest',
          size: 10,
          contexts: {
            location: {
              lat: 43.662,
              lon: -79.38
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "place",
  suggest: {
    place_suggestion: {
      prefix: "tim",
      completion: {
        field: "suggest",
        size: 10,
        contexts: {
          location: {
            lat: 43.662,
            lon: -79.38,
          },
        },
      },
    },
  },
});
console.log(response);
POST place/_search
{
  "suggest": {
    "place_suggestion": {
      "prefix": "tim",
      "completion": {
        "field": "suggest",
        "size": 10,
        "contexts": {
          "location": {
            "lat": 43.662,
            "lon": -79.380
          }
        }
      }
    }
  }
}

当在查询时指定较低精度的位置时,将考虑该区域内的所有建议。

如果在查询中设置了多个类别或类别上下文,它们将合并为析取。这意味着如果建议包含至少一个提供的上下文值,则会匹配。

位于由地理散列表示的区域内的建议也可以比其他建议得到更高的提升,如下所示

resp = client.search(
    index="place",
    pretty=True,
    suggest={
        "place_suggestion": {
            "prefix": "tim",
            "completion": {
                "field": "suggest",
                "size": 10,
                "contexts": {
                    "location": [
                        {
                            "lat": 43.6624803,
                            "lon": -79.3863353,
                            "precision": 2
                        },
                        {
                            "context": {
                                "lat": 43.6624803,
                                "lon": -79.3863353
                            },
                            "boost": 2
                        }
                    ]
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'place',
  pretty: true,
  body: {
    suggest: {
      place_suggestion: {
        prefix: 'tim',
        completion: {
          field: 'suggest',
          size: 10,
          contexts: {
            location: [
              {
                lat: 43.6624803,
                lon: -79.3863353,
                precision: 2
              },
              {
                context: {
                  lat: 43.6624803,
                  lon: -79.3863353
                },
                boost: 2
              }
            ]
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "place",
  pretty: "true",
  suggest: {
    place_suggestion: {
      prefix: "tim",
      completion: {
        field: "suggest",
        size: 10,
        contexts: {
          location: [
            {
              lat: 43.6624803,
              lon: -79.3863353,
              precision: 2,
            },
            {
              context: {
                lat: 43.6624803,
                lon: -79.3863353,
              },
              boost: 2,
            },
          ],
        },
      },
    },
  },
});
console.log(response);
POST place/_search?pretty
{
  "suggest": {
    "place_suggestion": {
      "prefix": "tim",
      "completion": {
        "field": "suggest",
        "size": 10,
        "contexts": {
          "location": [             
                      {
              "lat": 43.6624803,
              "lon": -79.3863353,
              "precision": 2
            },
            {
              "context": {
                "lat": 43.6624803,
                "lon": -79.3863353
              },
              "boost": 2
            }
          ]
        }
      }
    }
  }
}

上下文查询会筛选精度为 2(43.662, -79.380) 的地理散列所表示的地理位置下的建议,并提升默认精度为 6(43.6624803, -79.3863353) 的地理散列表示的建议,提升因子为 2

如果建议条目匹配多个上下文,则最终得分将计算为任何匹配上下文产生的最大得分。

除了接受上下文值之外,上下文查询还可以由多个上下文子句组成。对于 geo 上下文子句,支持以下参数

context

用于过滤或提升建议的地理点对象或地理散列字符串。这是必需的。

boost

建议的分数应提升的因子,分数是通过将提升因子与建议权重相乘来计算的,默认为 1

precision

用于编码查询地理位置点的地理哈希精度。可以将其指定为距离值(例如,5m10km 等),或者指定为原始地理哈希精度(1..12)。默认为索引时间精度级别。

邻居

接受一个精度值数组,用于指定应考虑哪些相邻的地理哈希。精度值可以是距离值(例如,5m10km 等),或原始地理哈希精度(1..12)。默认为生成索引时间精度级别的邻居。

精度字段不会导致距离匹配。指定类似 10km 的距离值只会产生一个表示该大小的瓦片的地理哈希精度值。该精度将用于将搜索地理位置点编码为地理哈希瓦片以进行完成匹配。这样做的一个后果是,即使非常靠近搜索点的瓦片之外的点也不会被匹配。降低精度或增加距离可以降低这种情况发生的风险,但不能完全消除它。

返回建议器的类型

编辑

有时你需要知道建议器的确切类型才能解析其结果。typed_keys 参数可以用来更改响应中建议器的名称,使其以其类型为前缀。

考虑以下示例,其中有两个建议器 termphrase

resp = client.search(
    typed_keys=True,
    suggest={
        "text": "some test mssage",
        "my-first-suggester": {
            "term": {
                "field": "message"
            }
        },
        "my-second-suggester": {
            "phrase": {
                "field": "message"
            }
        }
    },
)
print(resp)
response = client.search(
  typed_keys: true,
  body: {
    suggest: {
      text: 'some test mssage',
      "my-first-suggester": {
        term: {
          field: 'message'
        }
      },
      "my-second-suggester": {
        phrase: {
          field: 'message'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  typed_keys: "true",
  suggest: {
    text: "some test mssage",
    "my-first-suggester": {
      term: {
        field: "message",
      },
    },
    "my-second-suggester": {
      phrase: {
        field: "message",
      },
    },
  },
});
console.log(response);
POST _search?typed_keys
{
  "suggest": {
    "text" : "some test mssage",
    "my-first-suggester" : {
      "term" : {
        "field" : "message"
      }
    },
    "my-second-suggester" : {
      "phrase" : {
        "field" : "message"
      }
    }
  }
}

在响应中,建议器的名称将分别更改为 term#my-first-suggesterphrase#my-second-suggester,反映每个建议的类型

{
  "suggest": {
    "term#my-first-suggester": [ 
      {
        "text": "some",
        "offset": 0,
        "length": 4,
        "options": []
      },
      {
        "text": "test",
        "offset": 5,
        "length": 4,
        "options": []
      },
      {
        "text": "mssage",
        "offset": 10,
        "length": 6,
        "options": [
          {
            "text": "message",
            "score": 0.8333333,
            "freq": 4
          }
        ]
      }
    ],
    "phrase#my-second-suggester": [ 
      {
        "text": "some test mssage",
        "offset": 0,
        "length": 16,
        "options": [
          {
            "text": "some test message",
            "score": 0.030227963
          }
        ]
      }
    ]
  },
  ...
}

名称 my-first-suggester 现在包含 term 前缀。

名称 my-second-suggester 现在包含 phrase 前缀。