将精确搜索与词干提取结合使用
Elastic Stack Serverless
在构建搜索应用程序时,词干提取通常是必须的,因为希望对 skiing
的查询能够匹配包含 ski
或 skis
的文档。但是,如果用户想要专门搜索 skiing
呢?通常的做法是使用多字段,以便以两种不同的方式索引相同的内容
PUT index
{
"settings": {
"analysis": {
"analyzer": {
"english_exact": {
"tokenizer": "standard",
"filter": [
"lowercase"
]
}
}
}
},
"mappings": {
"properties": {
"body": {
"type": "text",
"analyzer": "english",
"fields": {
"exact": {
"type": "text",
"analyzer": "english_exact"
}
}
}
}
}
}
PUT index/_doc/1
{
"body": "Ski resort"
}
PUT index/_doc/2
{
"body": "A pair of skis"
}
POST index/_refresh
通过这种设置,在 body
上搜索 ski
将返回两个文档
GET index/_search
{
"query": {
"simple_query_string": {
"fields": [ "body" ],
"query": "ski"
}
}
}
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 2,
"relation": "eq"
},
"max_score": 0.18232156,
"hits": [
{
"_index": "index",
"_id": "1",
"_score": 0.18232156,
"_source": {
"body": "Ski resort"
}
},
{
"_index": "index",
"_id": "2",
"_score": 0.18232156,
"_source": {
"body": "A pair of skis"
}
}
]
}
}
另一方面,在 body.exact
上搜索 ski
将仅返回文档 1
,因为 body.exact
的分析链不执行词干提取。
GET index/_search
{
"query": {
"simple_query_string": {
"fields": [ "body.exact" ],
"query": "ski"
}
}
}
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.8025915,
"hits": [
{
"_index": "index",
"_id": "1",
"_score": 0.8025915,
"_source": {
"body": "Ski resort"
}
}
]
}
}
这不容易暴露给最终用户,因为我们需要找到一种方法来确定他们是否正在寻找精确匹配,并相应地重定向到适当的字段。如果只有部分查询需要精确匹配,而其他部分仍应考虑词干提取,该怎么办?
幸运的是,query_string
和 simple_query_string
查询具有一个功能,可以解决这个确切的问题:quote_field_suffix
。这告诉 Elasticsearch,出现在引号之间的单词将被重定向到另一个字段,请参见下文
GET index/_search
{
"query": {
"simple_query_string": {
"fields": [ "body" ],
"quote_field_suffix": ".exact",
"query": "\"ski\""
}
}
}
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.8025915,
"hits": [
{
"_index": "index",
"_id": "1",
"_score": 0.8025915,
"_source": {
"body": "Ski resort"
}
}
]
}
}
在上面的例子中,由于 ski
位于引号之间,因此由于 quote_field_suffix
参数,在 body.exact
字段上搜索了它,因此只有文档 1
匹配。这允许用户根据需要将精确搜索与词干提取搜索混合使用。
注意
如果在 quote_field_suffix
中传递的字段选择不存在,搜索将回退到使用查询字符串的默认字段。