elasticsearch中highlight的"假匹配"
一个highlight的假高亮现象:
/company_meta_info/_search?rest_total_hits_as_int=true
json
{
"_source": {
"includes": ["name","address"]
},
"query": {
"bool": {
"should": [
{
"match": {
"address": {
"query": "新疆蓝天七色建材有限公司",
"operator": "and"
}
}
}
]
}
},
"highlight": {
"fields": {
"name": {},
"address": {}
}
},
"from": 0,
"size": 10
}
返回结果:可以发现通过地址是没有匹配到任何结果
json
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 0,
"max_score": null,
"hits": []
}
}
换一种方式:先设法把文档召回
json
{
"_source": {
"includes": ["name","address"]
},
"query": {
"bool": {
"should": [
{
"match": {
"address": {
"query": "新疆蓝天七色建材有限公司",
"operator": "and"
}
}
},
{
"match": {
"org_id": "Q0000D2AC1" //此处匹配目标
}
}
]
}
},
"highlight": {
"fields": {
"name": {},
"address": {}
}
},
"from": 0,
"size": 10
}
返回结果:可以发现,结果并不是由于address字段命中召回的,但是highlight却有address,so 这是为什么尼
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 8.805375,
"hits": [
{
"_index": "company_meta_info_v6",
"_type": "_doc",
"_id": "Q0000D2AC1",
"_score": 8.805375,
"_source": {
"address": "新疆五家渠市北一东街1299号",
"name": "新疆蓝天七色建材有限公司"
},
"highlight": {
"address": [
"<em>新疆</em>五家渠市北一东街1299号"
]
}
}
]
}
}
这就需要了解elasticsearch中的高亮处理方式了。在elasticsearch中有三种高亮处理方式:highlighter, fast-vector-highlighter, postings-highlighter。默认使用的是highlighter方式。
highlighter 高亮也叫plain高亮,highlighter方式高亮是个实时分析处理高亮器。即用户在查询的时候,搜索引擎查询到了目标数据后,将需要高亮的字段数据提取到内存,再调用该字段的分析器进行处理,分析器对文本进行分析处理,分析完成后采用相似度算法计算得分最高的前n组并高亮段返回数据。
fast-vector-highlighter(fvh)高亮器利用建索引时候保存好的词项向量(term vector)来直接计算高亮段落,在高亮过程中比plain高亮方式少了实时分析过程,取而代之的是直接从磁盘中将分词结果直接读取到内存中进行计算。故要使用fvh的前置条件就是在建索引时候,需要配置存储词项向量,词向量需要包含词位置信息、词偏移量信息。
配置选项 | 描述 |
---|---|
no | 不启用term vector,默认值 |
yes | 启用term vector,但是仅仅记录分词 |
with_positions | 启用term vector, 记录分词及分词在字符串中的位置 |
with_offsets | 启用term vector, 记录分词在字符串中的起始字符位置 |
with_positions_offsets | 启用term vector, 记录分词在字符串中的位置及起始的字符位置 |
with_positions_payloads | 启用term vector, 记录分词在字符串中的位置及payloads |
with_positions_offsets_payloads | 启用term vector, 记录分词在字符串中的位置、起始字符位置及payloads |
fvh在高亮时候的逻辑如下:
1.分析高亮查询语法,提取表达式中的高亮词集合
2.从磁盘上读取该文档字段下的词向量集合
3.遍历词向量集合,提取自表达式中出现的词向量
4.根据提取到目标词向量读取词频信息,根据词频获取每个位置信息、偏移量
5.通过相似度算法获取得分较高的前n组高亮信息
6.读取字段内容(多字段用空格隔开),根据提取的词向量直接定位截取高亮字段
postings-highlighter(postings)。postings 高亮方式与fvh相似,采用词量向量的方式进行高亮,与fvh高亮不同的是postings高亮只存储了词向量的位置信息,并未存储词向量的偏移量,故中大字段存储中,postings其比fvh节省约20-30%的存储空间,速度与fvh基本相当。
so 由上述的表述我们就知道了,plain类型高亮方式,是首先召回文档,然后对文档进行高亮处理,在高亮处理的过程中并不会参考我们query中的配置条件("operator": "and");所以才会出现我们上面例子中的现象。单靠address条件并不会召回目标文档;当我们用其他条件召回了目标文档时,会进行高亮处理。
我们并不能单纯的将highlight的结果当成文档的匹配原由,想要了解匹配原理还是要通过explain
。