标签:维护 github使用 存储 延迟 讲解 展示 hub source sql语句
为了提高搜索命中率和准确率,改善现有羸弱的搜索功能,公司决定搭建全文搜索服务。由于之前缺乏全文搜索使用经验,经过一番折腾,终于不负期望按期上线。总结了一些使用心得体会,希望对大家有所帮助。计划分三篇:
说到全文搜索大家肯定会想到solr和elasticsearch(以下简称es),两者都是基于lucence,到底有什么区别呢?主要列出四个方面:
对比项 | solr | elasticsearch |
分布式 | 利用zookeeper进行分布式协调 | 自带分布式协调能力 |
数据格式 | 支持更多的数据格式(XML、JSON、CSV等) | 仅支持JSON |
查询性能 | 更适合偏传统的搜索应用,单纯对已有数据进行搜索性能更高,但实时建立索引时查询性能较差。 | 在实时搜索应用中表现更好,数据导入性能更好 |
数据量对查询性能影响 | 明显下降 | 影响不大 |
最终选择es,主要原因:
默认分词器对英文支持较好,但对中文不友好,会把中文拆分成一个个汉字,这显然不满足需求。
市面上中文分词器不少,该如何选择,主要考虑以下几点:
基于以上几点,很容易想到IK分词器,IK提供了两种分词模式:
分词模式 | 描述 |
ik_max_word |
会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌” 拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”, 会穷尽各种可能的组合 |
ik_smart | 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌” |
IK分词器项目地址:https://github.com/medcl/elasticsearch-analysis-ik
分词是否合理直接影响搜索结果的精确度,因此词库的更新尤为重要,由于es服务刚刚搭建完成,存在以下几个问题:
针对以上问题,提出了几个解决方案,后续逐步优化解决:
抛出一个问题:由于词库更新后需要重建索引才能使已有数据按照新的词库分词,在数据量较小的情况下没有问题,一旦数据达到一定量级,重建索引的成本较高。百度这种量级的数据是如何应对词库更新的呢?可在评论区留言一起探讨。
这里的数据同步是指将数据从mysql同步到es。主要有几种方式:
模式描述 | 代表 | 优点 | 缺点 |
服务定期扫表,通过时间戳字段实现同步 | logstash | 支持全量和增量同步,索引重建更方便 | 存在一定数据延迟,最少一分钟同步一次,且无法感知sql的delete操作 |
将自身伪装成mysql从库,监控binlog日志实现同步 | go-mysql-elasticsearch | 实时性较高 | 全量同步较困难,增加mysql服务器的同步成本 |
结合实际情况,会有定期重建索引需求,线上数据只允许逻辑删除,且对数据实时性要求并不高,公司的日志平台是通过logstash实现的日志收集,故选择logstash。
公司正在做微服务拆分,且索引往往涉及多条业务线的数据。拿商品举例,主要包含基本信息(实时性要求较高)、统计数据(商品购买量、评论量、浏览量等,实时性要求不高)。所以最终决定借助大数据平台,实时数据10分钟做一次增量同步,统计数据一天一次同步,数据整理成宽表吐到mysql库,然后利用logstash将数据同步到es。
搜索是全文索引的核心,下面列出了一些常用的搜索模式,为了便于理解,下面将各搜索语句类比成sql。
如果说上面的基本搜索类比成整条sql语句的骨架,那么Query DSL就是where条件,主要有以下几种类型语句:
类型 | 描述 |
Match Query | 全文模糊匹配 |
Match Phrase Query | 短语匹配,和Match Query类似,但要求索引词的先后顺序与输入搜索词的顺序一致。完全一致条件似乎比较严苛,可通过slop参数控制短语相隔多久也能匹配。 |
Match Phrase Prefix Query | 与短语匹配一致,支持在输入文本的最后一个词项上的前缀匹配,常用于根据用户输入的即时查询,例如淘宝搜索框输入关键字后的下拉展示。 |
Multi Match Query |
多字段搜索。包含以下几种模式: |
... |
类型 | 描述 |
Term Query | 术语精确搜索,将关键字当成一个词来处理。 1、如果字段为keyword类型,即是字段的精确匹配。 2、如果字段为text类型,则仅当搜索词按ik_smart模式分词后只得到一个词的情况下才有可能搜索到文档。 |
Terms Query | 同上,允许入参多个词。 |
Range Query | 范围搜索,常用语数值和时间格式。类似sql的between子句。 |
Exists Query | 搜索包含指定字段的文档。 |
Prefix Query | 前缀搜索,常用于实现下拉框输入的即时搜索。 |
Wildcard Query | 通配符搜索。通过通配符匹配词条。 |
Regexp Query | 正则表达式搜索。通过正则表达式匹配词条。 |
... |
模式 | 描述 | 参数介绍 |
Bool Query | 布尔搜索,由一个或多个类型化的Bool子句构成 |
must:用于搜索命中文档,条件组合是“and”关系,并且影响评分。 |
Function Score Query | 自定义函数评分搜索 |
score_mode:自定义函数分值计算模式,包含 Multiply(相乘)、Sum(求和)、Avg(平均)、First(第一个)、Max(最大)、Min(最小)。 boost_mode:搜索结果分值与自定义函数分值结合得到最终分值的模式,包含 Multiply(相乘)、Replace(仅使用函数分值)、Sum(求和)、Avg(平均)、Max(最大)、Min(最小)。 field_value_factor:字段值因素,例如文章阅读量、评论量影响分值。 其他:Weight(权重)、Decay functions(衰变函数)、Random score(随机评分) |
总结:以上对各种搜索模式做了简单介绍,每种模式里都包含一些搜索参数,没有具体展开。开发过程中往往需要结合实际情况,利用各种模式,设置搜索参数,配置字段权重,调优自定义函数分值,最终得到比较理想的搜索结果。
Talk is cheap, show me the code。
1 GET doctor_index/doctor_info/_search 2 { 3 "query1": {
4 "function_score": { 5 "query": { 6 "bool5": { 7 "must6": [ 8 { 9 "multi_match7": { 10 "query": "张内科", 11 "fields": [ 12 "doctor_name^2", 13 "department_name^1.2", 14 "doctor_skill^0.8", 15 "institution_name^1.4" 16 ], 17 "type8": "cross_fields", 18 "operator9":"and", 19 "analyzer10": "ik_smart" 20 } 21 } 22 ], 23 "must_not11": [ 24 { 25 "term12": { 26 "doctor_is_del": { 27 "value": "1" 28 } 29 } 30 } ] 39 } 40 }, 41 "functions13": [ 42 43 { 44 "script_score14": { 45 46 "script": { 47 "source15": "return Math.log(_score)/Math.log(2);" 48 } 49 } 50 }, { 65 "script_score": { 66 "script": { 67 "source": "String doctorProfessional = doc[‘doctor_professional‘].value; if (doctorProfessional == ‘主任医师‘) { return 1; } else if (doctorProfessional == ‘副主任医师‘) { return 0.8; } else if (doctorProfessional == ‘主治医师‘) { return 0.6; } else if (doctorProfessional == ‘住院医师‘) { return 0.4; } return 0;" 68 } 69 } 70 } ], 86 "boost_mode16": "replace", 87 "score_mode17": "sum" 90 }, 91 "min_score2":3, 92 "sort3": [ 93 { 94 "_score": { 95 "order": "desc" 96 } 97 }, 98 { 99 "doctor_name": { 100 "order": "desc" 101 } 102 } 103 ], 104 "explain4": true 105 }
分析如下:
一句话解释:使用自定义函数搜索模式,定义Bool组合搜索条件,将doctor_name等四个字段按照不同的权重组合成一个大字段,搜索同时满足“张内科”关键字按照ik_smart分词后的结果,将关键字搜索得到的分值取对数后加上医生职称的分值作为最终分值,然后过滤掉doctor_is_del=1和分值小于3分的文档,最后按照最终分值和doctor_name两个字段降序排列,默认取10条记录,并且展示分值计算过程。
是不是觉得很酸爽,这是提条相对复杂的语句,细细体会。
评分计算主要跟以下三个因素相关:
es还提供了其他强大的API功能,在此就不一一赘述了,例如:
建议使用官方推荐的RestHighLevelClient SDK按照以下流程开发。
标签:维护 github使用 存储 延迟 讲解 展示 hub source sql语句
原文地址:https://www.cnblogs.com/awalyslearning/p/9900635.html