elasticsearch实战应用

news2025/2/22 18:42:55

Elasticsearch(ES)是一种基于分布式存储的搜索和分析引擎,目前在许多场景得到了广泛使用,比如维基百科和github的检索,使用的就是ES。本文总结了一些使用心得体会,希望对大家有所帮助。

一、技术选型

说到全文搜索大家肯定会想到solr和elasticsearch(以下简称es),两者都是基于lucence,到底有什么区别呢?主要列出四个方面:

对比项solrelasticsearch
分布式利用zookeeper进行分布式协调自带分布式协调能力  
数据格式支持更多的数据格式(XML、JSON、CSV等)仅支持JSON
查询性能更适合偏传统的搜索应用,单纯对已有数据进行搜索性能更高,但实时建立索引时查询性能较差。在实时搜索应用中表现更好,数据导入性能更好
数据量对查询性能影响明显下降影响不大

  最终选择es,主要原因:

  1. 作为后起之秀,吸收了solr的优秀设计,在实时搜索上性能更佳,大有超越solr之势。
  2. 社区非常活跃,文档齐全,越来越多的应用从solr迁移至es。典型案例较多:GitHub使用es来检索超过1300亿行代码、Wikipedia 使用es提供带有高亮片段的全文搜索。

二、基本概念

  1. 集群(cluster)和节点(node):一个集群里包含多个节点,其中一个主节点通过选举产生,集群中任一节点的通信与整个es集群通信是等价的。
  2. 索引(index):es包含一个或多个索引,相当于关系型数据库(以下简称RDS)里的数据库,可以向索引里写入或读取数据。
  3. 类型(type):一个索引包含一个或多个type,相当于RDS里的表。
  4. 文档(document):相当于RDS里的数据行,文档没有固定的格式(schemaless),与mongodb很类似。
  5. 分片(shards):可以把一个大索引拆分成多个分片,分布到不同的节点上,提高检索效率。分片数在创建索引时确定,无法更改。
  6. 副本(replicas):副本有两个作用,一是增加容错,当某个分片损坏或丢失时可以由其他副本恢复;二是增加系统负载,当搜索流量增加可以通过动态增加副本来满足要求。
  7. 倒排索引(inverted index):由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。倒排索引时lucence核心数据存储结构。

三、中文分词

 3.1、分词器选型

默认分词器对英文支持较好,但对中文不友好,会把中文拆分成一个个汉字,这显然不满足需求。

市面上中文分词器不少,该如何选择,主要考虑以下几点:

  1. 自带默认词库,支持自定义词库扩展。
  2. 词库支持热更新(不重启es服务,自动生效)。
  3. 社区活跃,使用较广,分词效果好。

基于以上几点,很容易想到IK分词器,IK提供了两种分词模式:

分词模式描述
ik_max_word

会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”

拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,

会穷尽各种可能的组合

ik_smart会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”

IK分词器项目地址:GitHub - infinilabs/analysis-ik: 🚌 The IK Analysis plugin integrates Lucene IK analyzer into Elasticsearch and OpenSearch, support customized dictionary.

3.2、词库更新

分词是否合理直接影响搜索结果的精确度,因此词库的更新尤为重要,由于es服务刚刚搭建完成,存在以下几个问题:

  1. 词库更新不便捷、不及时。词库虽然支持热更新,但是需要DBA操作,产品和运营人员无法自行更新。
  2. 自定义词库相对单一。目前只有疾病库。
  3. 线上由于分词不当影响搜索结果的比例不低。举个例子:用户搜索“浙二医院”,显然是想搜“浙大医学院附属第二医院”,但是现有词库利用ik_smart模式拆分成“浙”、“二医院”两个词,显然不符合需求。
  4. 重建索引不方便。由于词库更新后需要重建索引才能使已有数据按照新的词库分词,目前也是需要DBA手动操作,增加了风险。

针对以上问题,提出了几个解决方案,后续逐步优化解决:

  1. 某些专有名称(医生姓名、医院科室名称等)自动实时更新。
  2. 定期人为扩充词库,例如医院别名、科室别名、疾病症状等。
  3. 定期分析用户搜索记录,发现新词。
  4. 运营后台增加词库更新和重建索引功能,支持产品和运营人员自行维护词库。

抛出一个问题:由于词库更新后需要重建索引才能使已有数据按照新的词库分词,在数据量较小的情况下没有问题,一旦数据达到一定量级,重建索引的成本较高。百度这种量级的数据是如何应对词库更新的呢?可在评论区留言一起探讨。

四、数据同步

4.1、数据同步方式选择

这里的数据同步是指将数据从mysql同步到es。主要有几种方式:

  1. 调用es提供的api同步。这种方式最灵活、最实时,但是有一定的编码成本,主要适用于对索引数据实时性要求较高的场景。
  2. 同步工具。开源的同步工具也不少,主要有两种模式:
模式描述代表优点缺点
服务定期扫表,通过时间戳字段实现同步logstash支持全量和增量同步,索引重建更方便存在一定数据延迟,最少一分钟同步一次,且无法感知sql的delete操作
将自身伪装成mysql从库,监控binlog日志实现同步go-mysql-elasticsearch实时性较高全量同步较困难,增加mysql服务器的同步成本

结合实际情况,会有定期重建索引需求,线上数据只允许逻辑删除,且对数据实时性要求并不高,公司的日志平台是通过logstash实现的日志收集,故选择logstash。

4.2、现有同步方式

现有服务器正在做微服务拆分,且索引往往涉及多条业务线的数据。拿商品举例,主要包含基本信息(实时性要求较高)、统计数据(商品购买量、评论量、浏览量等,实时性要求不高)。所以最终决定借助大数据平台,实时数据10分钟做一次增量同步,统计数据一天一次同步,数据整理成宽表吐到mysql库,然后利用logstash将数据同步到es。

五、搜索API

搜索是全文索引的核心,下面列出了一些常用的搜索模式,为了便于理解,下面将各搜索语句类比成sql。

5.1、基本搜索(搜索骨架)

  1. Query。使用Query DSL(Domain Specific Language领域特定语言)定义一条搜索语句。
  2. From/Size。分页搜索,类似sql的limit子句。
  3. Sort。排序,支持一个或多个字段,类似sql的order by子句。
  4. Sourcing Filter。字段过滤,支持通配符,类似sql的select字段。
  5. Script Fields。使用脚本基于现有字段虚构出字段。例如索引里包含first name和second name两个字段,使用Script Fields可以虚构出一个full name是first name和second name的组合。
  6. Doc Value Fields。字段格式化,例如Date格式化成字符串,支持自定义格式化类型。
  7. Highlighting。高亮。
  8. Rescoring。再评分,仅对原始结果的Top N(默认10)进行二次评分。
  9. Explain。执行计划,主要列出文档评分的过程。类似mysql的explain查看执行计划。
  10. Min Score。指定搜索文档的最小分值,实现过滤。
  11. Count。返回符合条件的文档数量。

5.2、核心搜索(Query DSL)

 如果说上面的基本搜索类比成整条sql语句的骨架,那么Query DSL就是where条件,主要有以下几种类型语句:

  • 全文搜索(Full Text Query)。文档地址:Full text queries | Elasticsearch Guide [8.15] | Elastic
类型描述
Match Query全文模糊匹配
Match Phrase Query短语匹配,和Match Query类似,但要求索引词的先后顺序与输入搜索词的顺序一致。完全一致条件似乎比较严苛,可通过slop参数控制短语相隔多久也能匹配。
Match Phrase Prefix Query与短语匹配一致,支持在输入文本的最后一个词项上的前缀匹配,常用于根据用户输入的即时查询,例如淘宝搜索框输入关键字后的下拉展示。
Multi Match Query

多字段搜索。包含以下几种模式:
1、best_fields:为每个字段分别生成Match Query搜索语句,然后取评分最高的字段作为文档最终得分。
2、most_fields:为每个字段分别生成Match Query搜索语句,然后将各分值相加然后除以命中语句数,得到文档最终得分。
3、phrase and phrase_prefix:行为跟best_fields一致,但使用 Match Phrase Query 代替 Match Query。
4、cross_fields:将多字段合并成一个大字段搜索。

  •  词条搜索(Term Level Query)。文档地址:Term-level queries | Elasticsearch Guide [8.15] | Elastic
类型描述
Term Query术语精确搜索,将关键字当成一个词来处理。
1、如果字段为keyword类型,即是字段的精确匹配。
2、如果字段为text类型,则仅当搜索词按ik_smart模式分词后只得到一个词的情况下才有可能搜索到文档。
Terms Query同上,允许入参多个词。
Range Query范围搜索,常用语数值和时间格式。类似sql的between子句。
Exists Query搜索包含指定字段的文档。
Prefix Query前缀搜索,常用于实现下拉框输入的即时搜索。
Wildcard Query通配符搜索。通过通配符匹配词条。
Regexp Query正则表达式搜索。通过正则表达式匹配词条。
  • 组合搜索(Compound Query)。主要是对以上搜索语句的各种组合,主要介绍Bool Query和Function Score Query,文档地址:Compound queries | Elasticsearch Guide [8.15] | Elastic
模式描述参数介绍
Bool Query布尔搜索,由一个或多个类型化的Bool子句构成

must:用于搜索命中文档,条件组合是“and”关系,并且影响评分。
filter:用于过滤文档,不同于must,不会对评分有任何影响。
should:如果Bool Query包含must或filter子句,则该子句主要用于评分;否则用于搜索命中文档。可通过minimum_should_match(至少匹配几个条件)参数控制该行为。
must not:与must作用相反,且不会影响评分。

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(随机评分)

总结:以上对各种搜索模式做了简单介绍,每种模式里都包含一些搜索参数,没有具体展开。开发过程中往往需要结合实际情况,利用各种模式,设置搜索参数,配置字段权重,调优自定义函数分值,最终得到比较理想的搜索结果。
 

5.3、示例实战

  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 }

 分析如下:

  • 1、定义一个Function Score Query子句。
  • 2、指定筛选文档的最低分值为3。
  • 3、文档优先按分值降序排,分值相同的情况下按doctor_name降序排。
  • 4、展示评分过程的执行计划。
  • 5、定义Bool Query的组合搜索模式。
  • 6、定义Bool Query的must子句。
  • 7、定义多字段搜索,搜索关键字“张内科”,搜索字段:doctor_name权重2、department_name权重1.2、doctor_skill权重0.8、institution_name权重1.4。
  • 8、定义多字段搜索类型为cross_fields,将以上四个字段合并成一个大字段处理。
  • 9、定义关键字and搜索,即只有分词后多字段同时出现才满足命中条件。
  • 10、定义使用ik_smart分词模式拆分搜索词。
  • 11、定义Bool Query的must_not子句。
  • 12、过滤掉doctor_is_del=1的文档。
  • 13、定义具体的自定义函数数组。
  • 14、定义一条评分规则。
  • 15、定义评分函数逻辑,将Query计算后的分值做对数运算。
  • 16、指定使用自定义函数分值作为文档的最终分值。
  • 17、指定多个自定义函数使用相加的方式计算分值。

一句话解释:使用自定义函数搜索模式,定义Bool组合搜索条件,将doctor_name等四个字段按照不同的权重组合成一个大字段,搜索同时满足“张内科”关键字按照ik_smart分词后的结果,将关键字搜索得到的分值取对数后加上医生职称的分值作为最终分值,然后过滤掉doctor_is_del=1和分值小于3分的文档,最后按照最终分值和doctor_name两个字段降序排列,默认取10条记录,并且展示分值计算过程。

是不是觉得很酸爽,这是提条相对复杂的语句,细细体会。

5.4、评分机制

评分计算主要跟以下三个因素相关:

  1. 词频。词在文档中出现的次数越多,分值越高。
  2. 逆向文档频率。词在所有文档里出现的频率越高,分值越低。
  3. 字段长度归一值。字段长度越短,分值越高。

5.5、其他API

es还提供了其他强大的API功能,在此就不一一赘述了,例如:

  • 文档管理API
  • 索引管理API
  • 聚合搜索API
  • 集群信息API

六、开发流程

建议使用官方推荐的RestHighLevelClient  SDK按照以下流程开发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2147284.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件测试 BUG 篇

目录 一、软件测试的生命周期 二、BUG 1. bug的概念 2. 描述bug的要素 3. bug的级别 4. bug的生命周期 5. 与开发产生争执怎么办?(面试高频考题) 5.1 先检查自身,是否bug描述不清楚 5.2 站在用户角度考虑并抛出问题 5.3 …

[vue2+axios]下载文件+文件下载为乱码

export function downloadKnowledage(parameter) {return axios({url: /knowledage/download,method: GET,params: parameter,responseType: blob}) }添加 responseType: blob’解决以下乱码现象 使用触发a标签下载文件 downloadKnowledage(data).then((res) > {let link …

PHP及Java等其他语言转Go时选择GoFly快速快速开发框架指南

概要 经过一年多的发展GoFly快速开发框架已被一千多家科技企业或开发者用于项目开发,他的简单易学得到其他语言转Go首选框架。且企业版的发展为GoFly社区提供资金,这使得GoFly快速框架得到良好的发展,GoFly技术团队加大投入反哺科技企业和开…

模版进阶(template)

1.非类型模版参数 模版参数分类类型形参与非类型形参。 ① 类型形参:出现在在模板参数列表中,跟在class或者typename之类的参数类型名称。 ② 非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当…

Java键盘输入语句

编程输入语句 1.介绍:在编程中,需要接受用户输入的数据,就可以使用键盘输入语句来获取。 2.步骤: 1)导入该类的所在包,java.util.* 2)创建该类对象(声明变量) 3)调用里面的功能 3…

[2025]医院健康陪诊系统(源码+定制+服务)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

计算机毕业设计 奖学金评定管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

MySQL ------- 索引(B树B+树)

阿华代码,不是逆风,就是我疯,希望本文内容能帮到你!你们的点赞收藏是我前进最大的动力!! 目录 一:索引的特点 二:索引适用的场景 三:MySQL中索引操作 1:…

LTE SSS辅同步信号检测(相关法)

本文介绍一下SSS检测原理,本文采用联合检测算法,用复杂度来换取性能,适合工程上使用,SSS信号的产生往期已经介绍过了,这里就不介绍了。 1 SSS两个序列采用Interleaved结构而没有采用Localized集中式的原因是他比集中式可以获得更大的频率分集和干扰随机化效果。 2 根据3…

Python 从入门到实战22(类的定义、使用)

我们的目标是:通过这一套资料学习下来,通过熟练掌握python基础,然后结合经典实例、实践相结合,使我们完全掌握python,并做到独立完成项目开发的能力。 上篇文章我们讨论了面向对象简单介绍相关知识。今天我们将学习一…

828华为云征文 | 深度评测,华为云Flexus X实例在Sysbench性能测试中的亮眼表现

前言 本文章评测了华为云Flexus X实例在Sysbench性能测试中的亮眼表现。Flexus X凭借其新一代处理器和智能算力技术,在CPU、内存、磁盘I/O及网络性能上均展现出了卓越的能力。通过Sysbench的详尽测试,Flexus X实例在多核计算能力、内存吞吐量、磁盘响应速…

CSS传统布局方法(补充)——WEB开发系列37

开发技术不断演进,布局方式也经历了多个阶段的变革。从最初的基于表格布局到 CSS 的浮动布局,再到今天的弹性盒(Flexbox)与 CSS Grid 网格布局,每一种布局方式都有其独特的背景和解决特定问题的优势。 一、CSS Grid 出…

neo4j安装启动教程+对应的jdk配置

参考这位博主的视频教程:neo4j社区windows版下载 一、官网下载neo4j的安装包 (1)官网下载页面 (2)上一步 【download】之后,会自动下载,如果没有,点击【here】 这里可以看到一行字…

IDEA Project不显示/缺失文件

问题:侧边栏project 模式下缺少部分文件 先点close project 打开项目所在目录,删除目录下的.idea文件夹 重新open project打开这个项目即可解决

stm32单片机个人学习笔记4(GPIO输入)

前言 本篇文章属于stm32单片机(以下简称单片机)的学习笔记,来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记,只能做参考,细节方面建议观看视频,肯定受益匪浅。 STM32入门教程-2023版 细…

JavaDS —— 图

图的概念 图是由顶点集合以及顶点之间的关系组成的一种数据结构:G (V,E) 其中 V 表示的是顶点集合 : V { x | x 属于某个数据对象集} 是有穷非空集合 E 叫做边的集合 : E {(x, y) | x, y 属于 V} 或者 …

深度长文:揭开C/C++三目运算符的全部秘密,助你写出更优雅的代码(下)

在上篇文章中,我们深入探讨了三目运算符的基础语法、与if-else的对比以及使用中的常见误区。通过这些知识,你已经掌握了如何在代码中使用三目运算符来简化条件判断。 然而,三目运算符在C和C中的应用并不仅限于简单的条件选择。接下来&#x…

尚品汇-秒杀下单实现-页面轮询查询订单状态(五十三)

目录: (1)整合秒杀业务 (2)秒杀下单 (3)秒杀下单监听 (4)页面轮询接口 (1)整合秒杀业务 秒杀的主要目的就是获取一个下单资格,拥…

《深度学习》—— 神经网络模型对手写数字的识别

神经网络模型对手写数字的识别 import torch from torch import nn # 导入神经网络模块 from torch.utils.data import DataLoader # 数据包管理工具,打包数据, from torchvision import datasets # 封装了很多与图像相关的模型,数据集 from torchvi…

codetop字符串刷题,刷穿地心!!不再畏惧!!暴打面试官!!

主要供自己回顾与复习,题源codetop标签字符串近半年,会不断更新 1.有效的括号字符串2.括号生成3.最长单词4.字符串转换整数(atoi)5.整数转罗马数字6.罗马数字转整数7.比较版本号8.最长公共前缀9.面试题17.15.最长单词10.验证IP地址11.面试题01.06.字符串…