ik分词与match_phrase短语匹配

栏目: 编程工具 · 发布时间: 7年前

内容简介:这两天遇到一个后台的检索需求,要求实现SQL中like “%xxxx%”的匹配效果。这种效果在ES中最匹配的做法是用效果最差的做法是用match全文检索,这种情况只要query分词的任何一个term出现在倒排中,就会召回文档,所以很容易搜出一些八竿子打不着的文档。

这两天遇到一个后台的检索需求,要求实现 SQL 中like “%xxxx%”的匹配效果。

wildcard通配

这种效果在ES中最匹配的做法是用 wildcard query 通配,这种情况不会对query分词,而是直接遍历倒排索引逐个匹配计算,性能是无法想象的,大家慎用。

match全文匹配

效果最差的做法是用match全文检索,这种情况只要query分词的任何一个term出现在倒排中,就会召回文档,所以很容易搜出一些八竿子打不着的文档。

match_phrase短语匹配

推荐一个折衷性能与准确度的做法就是用 match_phrase 短语匹配。

match_phrase的原理是对query分词,要求所有的term都出现在倒排中,并且连续且顺序一致的排列,下面一起看个例子。

我们采用 ik_smart中文分词器 ,对”青岛上合蓝”分词:

[
            'index' => 'article',
            'body' => [
                'analyzer' => 'ik_smart',
                'text' => '青岛上合蓝',
            ]
]

得到结果:

{
	"tokens": [{
		"token": "青岛",
		"start_offset": 0,
		"end_offset": 2,
		"type": "CN_WORD",
		"position": 0
	}, {
		"token": "上合",
		"start_offset": 2,
		"end_offset": 4,
		"type": "CN_WORD",
		"position": 1
	}, {
		"token": "蓝",
		"start_offset": 4,
		"end_offset": 5,
		"type": "CN_WORD",
		"position": 2
	}]
}

大家看到,每个term都有一个position字段标识了term的位置,这将直接影响match_phrase是否可以召回。

接着我们进行搜索,query搜索词是:”上合蓝”,分词结果如下:

{
	"tokens": [{
		"token": "上合",
		"start_offset": 0,
		"end_offset": 2,
		"type": "CN_WORD",
		"position": 0
	}, {
		"token": "蓝",
		"start_offset": 2,
		"end_offset": 3,
		"type": "CN_WORD",
		"position": 1
	}]
}

“上合”与”蓝”的position紧密排列,与之前”青岛上合蓝”中的”上合”与”蓝”顺序一致且连续,所以match_phrase搜索”上合蓝”可以召回上述的”青岛上合蓝”。

相反,如果你query搜索”青岛蓝”,那么”青岛”与”蓝”中间少了一个”上合”,所以无法召回:

{
	"tokens": [{
		"token": "青岛",
		"start_offset": 0,
		"end_offset": 2,
		"type": "CN_WORD",
		"position": 0
	}, {
		"token": "蓝",
		"start_offset": 2,
		"end_offset": 3,
		"type": "CN_WORD",
		"position": 1
	}]
}

所以,match_phrase的确可以解决我们的这个场景。

因为match_phrase需要分词,所以如果分词效果不好(词库不足),query就会产生不同于doc的term,如果term都不同就肯定无法匹配了。

但是大家要注意, match_phrase与ik_max_word分词器是无法一起工作的 ,因为ik_max_word分词的term具有重叠问题,下面举个栗子:

先用ik_max_word分词:

[
            'index' => 'article',
            'body' => [
                'analyzer' => 'ik_max_word',
                'text' => '青岛上合蓝',
            ]
]

得到:

{
	"tokens": [{
		"token": "青岛",
		"start_offset": 0,
		"end_offset": 2,
		"type": "CN_WORD",
		"position": 0
	}, {
		"token": "岛上",
		"start_offset": 1,
		"end_offset": 3,
		"type": "CN_WORD",
		"position": 1
	}, {
		"token": "岛",
		"start_offset": 1,
		"end_offset": 2,
		"type": "CN_WORD",
		"position": 2
	}, {
		"token": "上合",
		"start_offset": 2,
		"end_offset": 4,
		"type": "CN_WORD",
		"position": 3
	}, {
		"token": "蓝",
		"start_offset": 4,
		"end_offset": 5,
		"type": "CN_WORD",
		"position": 4
	}]
}

你从”岛上”,”岛”就能看出,它的term之间具有重叠情况,这与ik_smart是完全不同的,因为ik_max_word的目标是尽可能产生更多的term组合,一般用于全文检索提高召回率。

接着我们搜索下面的query:

[
            'index' => 'article',
            'body' => [
                'analyzer' => 'ik_max_word',
                'text' => '青岛',
            ]
]

分词结果:

{
	"tokens": [{
		"token": "青岛",
		"start_offset": 0,
		"end_offset": 2,
		"type": "CN_WORD",
		"position": 0
	}, {
		"token": "岛",
		"start_offset": 1,
		"end_offset": 2,
		"type": "CN_WORD",
		"position": 1
	}]
}

“青岛”与”岛”之间差着一个”岛上”,结果就是match_phrase不匹配。

最后给大家一个结论:

如果大家用match_phrase的话,需要注意2个方面:1)分词器不准会影响召回;2)只能用ik_smart。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

A Philosophy of Software Design

A Philosophy of Software Design

John Ousterhout / Yaknyam Press / 2018-4-6 / GBP 14.21

This book addresses the topic of software design: how to decompose complex software systems into modules (such as classes and methods) that can be implemented relatively independently. The book first ......一起来看看 《A Philosophy of Software Design》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换