es 基于match_phrase的模糊匹配原理及使用
[版权声明]:本文章由danvid发布于http://danvid.cnblogs.com/,如需转载或部分使用请注明出处
在业务中经常会遇到类似数据库的"like"的模糊匹配需求,而es基于分词的全文检索也是有类似的功能,这个就是短语匹配match_phrase,但往往业务需求都不是那么简单,他想要有like的功能,又要允许有一定的容错(就是我搜索"东方宾馆"时,"广州花园宾馆酒店"也要出来,这个就不是单纯的"like"),下面就是我需要解析的问题(在此吐槽一下业务就是这么变态。。)
描述一个问题时首先需要描述业务场景:假设es中有一索引字段name存储有以下文本信息:
doc[1]:{"name":"广州东方宾馆酒店"}
doc[2]:{"name":"广州花园宾馆酒店"}
doc[3]:{"name":"东方公园宾馆"}
需求要求在输入:"东方宾馆"的时候doc[1]排最前面doc[3]排第二doc[2]排第三,对于这个需求从简单的全文检索match来说,doc[3]:{"name":"东方公园宾馆"}应该是第一位(注意:为了简化原理分析,分词我们使用standard即按单个字分词)
业务分析:显然对于上面的业务场景如果单独使用match的话,显然是不合适,因为按照standard分词,doc[3]的词条长度要比doc[1]的词条长度短,而词频又是都出现了[东][方][宾][馆]4个词,使用match匹配的话就会吧doc[3]排到最前面,显然业务希望把输入的文字顺序匹配度最高的数据排前面,因为我确实要找的是"广州东方宾馆酒店"而不是"东方公园宾馆"你不能把doc[3]给我排前面,OK业务逻辑好像是对的那么怎么解决问题;
解决问题前介绍一哈match_phrase原理(match的原理我就不说了自己回去看文档),简单点说match_phrase就是高级"like"。api如下:
GET test_index/_search
{
"query": {
"match_phrase" : {
"message" : {
"query" : "东方宾馆",
"slop" : 2
}
}
}
}
es在给文本分词的时候,除了分词之外还有一个词条标记,就是position,例如我按照standard对以上三个doc的name进行分词会变成这样:
doc[1]:广[0],州[1],东[2],方[3],宾[4],馆[5],酒[6],店[7]; doc[2]:广[0],州[1],花[2],园[3],宾[4],馆[5],酒[6],店[7]; doc[3]:东[0],方[1],公[2],园[3],宾[4],馆[5]; query文本分词:东[0],方[1],宾[2],馆[3];
使用match_phrase时:
1.es会先过滤掉不符合的query条件的doc,即doc[2]中没有"东方"两个词汇,会被过滤掉
2.es会根据分词的position对分词进行过滤和评分,这个是就slop参数,默认是0,意思是查询分词只需要经过距离为0的转换就可以变成跟doc一样的文档数据,例如:对于doc[1]来说slop就是0了,对于doc[3]slop就是2,即"宾"和"馆"最大位移这两个分词只需要最多移动2个位置就可以变成"东方宾馆"(反过来也一样,query的文本中的"宾"和"馆"只需要移动2个位置就可以变成"东方**宾馆"),用数学的理解就是doc[3]的宾[4]-东[0]=4,query文本中的宾[2]-东[0]=2,那么转换距离slop就是4-2=2,同理doc[3]的馆[5]-东[0]=5,query的是3,slop结果也是2,那么"宾"和"馆"最大的slop就是2,则query时设置slop等于2就能把doc[3]匹配出来,当设置为0时就是我们数据库的"like"
原理解析完了,就知道使用match只能匹配相关度即tf/idf,而分词之间的位置关系却无法保证,而match_phrase能保证分词间的邻近关系,那么就可以利用两者优势,结合搜索进行评分
GET test_index/_search
{
"query": {
"bool": {
"must": {
"match": {
"name": {
"query": "东方宾馆"
}
}
},
"should": {
"match_phrase": {
"name": {
"query": "东方宾馆",
"slop": 0
}
}
}
}
}
}
这样就的结果就是相当于match_phrase帮match进行了相关度分数的加分,当然你也可以通过修改slop的参数来进行步控制分数,这个就根据用户需求来了;
性能问题:其实使用match_phrase性能是要比单纯的全文检索性能低的,因为他要计算位置嘛,那么想提高性能可以通过先使用match进行过滤数据,然后利用rescore api对已经match的结果进行加分,这样就减少了部分不必要的非match过滤:
GET test_index/_search
{
"query": {
"match": {
"name":"东方宾馆"
}
},
"rescore": {
"window_size": 30,
"query": {
"rescore_query": {
"match_phrase": {
"name": {
"query": "东方宾馆",
"slop": 0
}
}
}
}
}
}
#window_size 是每一分片进行重新评分的顶部文档数量这个只要大于你可能分页的总数*每页的数量即可(pageNumber*pageSize)实际上不需要这么多因为翻页不可能很深,这个根据业务调整即可。
总结及注意点:
1.rescore其实跟bool结合一样是评分的相加,评分不在这里细说了;
2.虽然可以提高相关度评分,但是还是存在可能match很低+一个很低的match_phrase结果没有单独只匹配了一个match的分数高的情况,但是这是很极限了,也是符合相关度评分原理的;
3.由于match_phrase是在搜索阶段进行的计算,会影响搜索效率,据说比term查询慢20倍,所以不要进行大文本量的字段搜索,尽量进行标题,名字这种类型的搜索才使用这个;
4.本文章没有讨论在文本数据重复时的情况,即文本中有多个"[东][方][宾][馆]"和query文本中有多个"[东][方][宾][馆]"分词的情况,但是原理是一样的还是取距离转换的最小值;
5.文中使用了standard分词,实际上可能会用不同的分词器,但是建议使用match_phrase时使用标准的一个个分词,这样是方便进行邻近搜索的控制的,如果使用ik等分词,执行match_phrase时分词是不可控的,所以结果也是不可控。match使用ik,match_phrase用standard结合一起使用也是可以的;
6.邻近搜索效率较低,其实可以通过增加词库的方式进行单纯使用match匹配效率是最高的,前提是你知道客户会搜索什么,这又是另一个研究话题了
更新[2019-05-22]:
补充:短语匹配match_phrase必须要满足下面的要求才能认定和["东方宾馆"]这个词条匹配(以standard分析器为例)
1.搜索的词必须有且仅有["东","方","宾","馆"]这几个词(对于中文是字)的一个或者多个,如果有其他的词(对于中文是字)是不会匹配到的,slop不是完全等同于莱文斯坦距离,可以理解成字符的偏移
2.查询词中偏移量应该跟文档中词的偏移量一样,或者在slop的偏差范围内,就是上文解析的意思。
这里讲解一下fuzzy和match_phrase的区别
1.fuzzy是词/项级别的模糊匹配,match_phrase是基于短语级别的
例如对于英文(standard分析器)来说"dog cat bird"来说"dog"就是一个词/词项,而"dog cat"就是一个短语,因此作用范围不一样
2.fuzzy是基于莱文斯坦距离的,所以fuzzy是可以容错的例如你输入"dcg" 你也可以匹配到"dog cat bird",但是这里注意的是你的查询只能是单词条的查询,不能"dcg cat",如果你需要查询短语里面的拼写错误,可以使用match的fuzziness参数,match_phrase是不允许出现不存在的词条的。
下面是对于fuzzy和match_phrase和match 添加fuzziness参数进行对比
文档内容是{"name":"dog cat bird"} 分析器是standard
--------------------------------------------------------------------------------------------------
1.使用拼写错误的"cot"可以使用fuzzy匹配但是,如果是下面这种,短语是不可以的,输入应当是词条,而不是短语
GET test_save/_search
{
"query": {
"fuzzy": {
"name":{
"value": "bird cot",
"fuzziness":
}
}
}
}
--------------------------------------------------------------------------------------------------
2.这里可以匹配到因为match先分解成bird 和 cot 其中bird可以匹配到,同时cot也是可以匹配到,只不过分数要比输入"bird cat"要低
GET test_save/_search
{
"query": {
"match": {
"name":{
"query": "bird cot",
"fuzziness":
}
}
}
}
-----------------------------------------------------------------------------------------------
3.这里由于cot和文本中的cat不是同一个词,所以是无法匹配到的
GET test_save/_search
{
"query": {
"match_phrase": {
"name": {
"query": "bird cot",
"slop":
}
}
}
}
以上是对于英文的单词的解析,对于中文其实也是一样,只是由于中文如果使用standard一个词项就是一个字,因此使用因此分词后的数据对于fuzzy模糊匹配来说意义不大,但是可以使用keyword进行
GET test_save/_search
{
"query": {
"fuzzy": {
"name.keyword":{
"value": "东日宾馆",
"fuzziness":
}
}
}
}
这样是可以匹配到"东方宾馆"的数据的,但是无法匹配"广州东方宾馆"因为莱文斯坦距离已经不止1了
其实短语匹配应该叫临近查询更适合些
以上就是对模糊查询和短语匹配的解析和补充~
[说明]:elasticsearch版本5.6.4
es 基于match_phrase的模糊匹配原理及使用的更多相关文章
- 基于vue实现模糊匹配(这里以邮箱模糊匹配为例,其他的模糊匹配都可以类比)
html部分(主要部分): js: data: methods: 效果图:
- 转:使用Mongo Connector和Elasticsearch实现模糊匹配
原文来自于:http://www.csdn.net/article/2014-09-01/2821485-how-to-perform-fuzzy-matching-with-mongo-connec ...
- 记一个同时支持模糊匹配和静态推导的Atom语法补全插件的开发过程: 序
简介 过去的一周,都睡的很晚,终于做出了Atom上的APICloud语法提示与补全插件:apicloud_autocomplete.个中滋味,感觉还是有必要记录下来的.代码基于 GPL-3.0 开源, ...
- 茗洋Easy UI 1.3.2 部分问题解决系列专题[Combo模糊匹配中文问题 修复]
本次给大家带来的EasyUI的我研究拓展的新特性 我使用的是 EasyUI 1.3.2版本的,项目是ASP.NET MVC3,但是本篇讲解用不上ASP.NET MVC,仅仅修改官方Demo你就知道怎 ...
- Combo模糊匹配中文问题
茗洋Easy UI 1.3.2 部分问题解决系列专题[Combo模糊匹配中文问题 修复] 本次给大家带来的EasyUI的我研究拓展的新特性 我使用的是 EasyUI 1.3.2版本的,项目是ASP. ...
- Android自定义模糊匹配搜索控件(二)
在项目中遇到一个需要通过某个字的值筛选匹配带出其他信息的需求,在这里将实现思路整理出来. 源码地址:https://github.com/whieenz/SearchSelect 先看效果图 上图中的 ...
- 基于PaddlePaddle的语义匹配模型DAM,让聊天机器人实现完美回复 |
来源商业新知网,原标题:让聊天机器人完美回复 | 基于PaddlePaddle的语义匹配模型DAM 语义匹配 语义匹配是NLP的一项重要应用.无论是问答系统.对话系统还是智能客服,都可以认为是问题和回 ...
- mysql学习2:模糊匹配查询like,regexp,in
mysql模糊匹配查询like,regexp,in 摘要 内容比较简单,无摘要. 关键词 模糊查询 like regexp in contact 正文 下图是示例用到的数据表信息 ...
- JAVA基础之sql模糊匹配、外键以及jsp中include的用法
一.SQL模糊匹配 适用于对字符串进行模糊搜索 格式: 字段名 Like '%关键词%' % 表示这个位置可有任意个字符(没有也可以) %关键词% 只要包含关键词就算 ...
随机推荐
- cdnbest独立主控配置自定义错误页面
注:自定义错误的域名最好配置ssl,不配碰到有使用ssl的域名,错误码显示就会有问题 (1)登陆管理后台点区域列表-->配置-->错误url 解析一个域名到你的cdn主控,然后输入这个ur ...
- cdnbest架设cdn同一个源用不同的端口访问如何设置
在站点里的应用防火墙-->高级设置里配置 比如test.com要同时用80和88访问
- Spring使用fastjson处理json数据
1.搭建SpringMVC+spring环境 2.配置web.xml以及springmvc-config.xml,web.xml同Spring使用jackson处理json数据一样,Springmvc ...
- 单点登录(SSO)解决方案之 CAS 入门案例
单点登录: 单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. ...
- Spring注入静态变量的方法,以及CXF如何获取客户端IP
1.如果使用@Resource注解来注入静态变量的,服务器启动就会报错的.可以新增一个set方法,同时在set方法上用@Resource注解来注入. 2.或者直接在Spring的配置文件中使用< ...
- vue-if和v-show区别
vue-if和vue-show都是对条件进行判断,一直不明白他们的区别,知道看到了官方文档中的解释: v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和 ...
- windows下webstorm调试react native
安装请参考:http://www.cnblogs.com/wjx0912/p/5662457.html webstorm在2016.10.20的版本才正式增加react native的调试支持,所以w ...
- python2/3 利用psycopg2 连接postgreSQL数据库。
psycopg2 是一个通过python连接postgreSQL的库, 不要被它的名称蒙蔽了,你可能发现它的版本是psyconpg2.7.*, 以为它只能在python2上使用,实际上,这只是一个巧合 ...
- ----关于css中常见单位----
1.px 像素,绝对单位长度,可设定固定的长度大小.(像素是相对于显示器屏幕分辨率而言) 所有浏览器都显示为一样大小. eg: html: <p>这是一段正常段落</p> &l ...
- iPhone屏幕分辨率和适配规则 图片文字适配
基本概念 - 逻辑分辨率 pt (point),物理分辨率 px (pixel) - 缩放因子 scale 或者 dpr, scale ≈ px / pt - 缩放采样 例如 iPhone 6 Plu ...