Elasticsearch操作--笔记
索引库操作
mapping属性
mapping是对索引库中文档的约束,常见的mapping属性包括:
-type:字段数据类型,常见的简历类型有:
–字符串:text(可分词的文本)、keyword(精确值,不可拆分)
–数值:long、integer、short、byte、double、float
–布尔:boolean
–日期:date
–对象:object
-index:是否创建索引,默认为true(如果没有创建索引,就无法搜索)
-analyzer:使用哪种分词器
-properties:该字段的子字段
创建索引库
DSL创建索引库语法
PUT /索引库名称
{
"mappings":{
"properties":{
"字段名":{
"type":"text",
"analyzer":"ik_smart"
},
"字段名2":{
"type":"keyword",
"index":"false"
},
"字段名3":{
"properties":{
"type":"keyword"
}
}
}
}
}
查询、删除、修改索引库
查看索引库语法:
GET /索引库名
删除索引库语法:
DELETE /索引名
修改索引库:
索引库和mapping一旦创建无法修改,但是可以添加新的字段,语法:
PUT /索引库名/_mapping{
"properties":{
"新字段名":{
”type":"integer"
}
}
}
文档操作
添加文档
新增文档的DSL语法如下:
POST /索引库名/_doc/文档id
{
"字段1":“值1”,
"字段2":“值2”,
"字段3":{
"子属性1":"值3"
}
}
查看、删除文档
查看文档语法:
GET /索引库名/_doc/文档id
删除文档的语法
DELETE /索引库名/_doc/文档id
修改文档
方式一:全量修改,会删除旧文本,添加新文档
PUT /索引库名/_doc/文档id
{
"字段1":"值1",
"字段2":“值2”,
"字段3":{
"子属性1":"值3"
}
}
方式二:增量修改,修改指定字段值
POST /索引库名/_update/1{
"doc":{
"字段名":"修改后的值"
}
}
分布式搜索引擎
简单查询
DSL查询语法-DSL查询分类
elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型包括:
查询所有:查询出所有数据,一般测试用。例如:match_all
全文检索查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:match_query、multi_match_query
精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、Boolean等类型字段。例:ids、range、term
地理查询:根据经纬度查询。例如:geo_distance、geo_bounding_box
复合查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。例如:bool、function_score
DSL查询语法-DSL基础语法:
GET /indexName/_search
{
"query":{
"查询类型":{
"查询条件":“条件值”
}
}
}
例:查询所有match_all,不需要查询条件
GET /indexName/_search
{
"query":{
"match_all":{
}
}
}
DSL查询语法-全文检索查询
全文检索查询,会对用户输入内容分词,常用于搜索框搜索
match查询:全文检索查询的一种,会对用户输入内容分词,然后去倒排索引库检索,语法:
GET /indexName/_search
{
"query":{
"match":{
"FIELD":"TEXT"
}
}
}
multi_match:与match查询类似,只不过允许同时查询多个字段,语法:
GET /indexname/_search
{
"query":{
"multi_match":{
"query":"查询内容"
"fields":["查询字段名","查询字段名",....]
}
}
}
DSL查询语法-精确查询
精确查询一般是查找keyword、数值、日期、boolean等类型字段。所以不会对搜索条件分词。常见的有:
term:根据词条精确值查询
GET /indexName/_search
{
"query":{
"term":{
"查询字段名":{
"value":"查询值"
}
}
}
}
range:根据值的范围查询
GET /indexName/_search
{
"query":{
"range":{
"查询字段名":{
"gte":"大于等于的值", #gt-----大于
"lte":"小于等于的值" #lt-----小于
}
}
}
}
DSL查询语法-地理查询
根据经纬度查询,常见的使用场景(搜索附件的酒店,打车)
geo_bounding_box:查询geo_point值落在某个矩形范围的所有文档
GET /indexName/_search
{
"query":{
""geo_bounding_box"":{
"FIELD":{ #查询字段名
"top_left":{ #矩形左上角的点位置
"lat":31.1,
"lon":121.5
},
"bottom_right":{ #矩形右下角的点的位置,根据这两个点构成一个矩形,然后查询在这个矩形范围内的数据
"lat":30.9,
"lon":121.7
}
}
}
}
}
geo_distance:查询到指定中心点小于某个距离值的所有文档
GET /indexName/_search
{
"query":{
"geo_distance":{
"distance":"15km", #半径
"查询字段名":“31.21,121,5” #圆点,以这个圆点和半径画圈,位置在圈内的数据
}
}
}
复合查询
复合查询可以将其他简单查询组合起来,实现更复杂的搜索逻辑。例:
function score:算分函数查询,可以控制文档相关性算分,控制文档排名
DSL查询语法-相关性算分
当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排序。
TF(词条频率)=词条出现次数/文档中词条总数
DSL查询语法-FunctionScoreQuery
使用functionscorequery,可以修改文档的相关性算分(query score),根据新得到的算分排序
functionscorequery三要素:1.过滤条件:哪些文档需要加分;2.算分函数:如何计算functionscore;3.加权方式:function score 与query score如何运算
DSL查询语法-BooleanQuery
布尔查询是一个或多个查询子句的组合。子查询的组合方式有:
must:必须匹配每个子查询,类似“与”
should:选中性匹配子查询,类似“或”
must_not:必须不匹配,不参与算分,类似“非”
filter:必须匹配,不参与算分
GET /indexName/_search
{
“query”:{
"bool":{
"must":[
{"term":{"city":"上海"}}
],
"should":[
{"term":{"brand":"皇冠"}},
{"term":{"brand":"华美达"}}
],
"must_not":[
{"range":{"price":{"lte":500}}}
],
"filter":[
{"range":{"score":{"gte":45}}}
],
}
}
}
搜索结果处理
排序
elasticsearch支持对搜索结果排序,默认是根据相关度算分(_score)来排序。可以排序字段类型有:keyword类型(字符串,按字母排序)、数值类型、地理坐标类型、日期类型等。(指定排序后,elasticsearch就不会再计算相关性)
例:
GET /indexName/_search
{
"query":{
"match_all":{}
},
"sort":[
{
"排序字段名":“排序方式” //排序方式ASC、DESC
},
{
"排序字段名":“排序方式” //排序方式ASC、DESC
}
]
}
GET /indexName/_search
{
"query":{
"match_all":{}
},
"sort":{
"_geo_distance":{
"排序字段名":”维度,经度“, #维度,经度是指定地址,按照排序字段距离该指定地址的距离排序
”order“:"asc", #排序方式
"unit":"km" #单位
}
}
}
分页
elasticsearch默认情况下只返回Top10的数据,而如果要查询更多数据就需要修改分页参数了。elasticsearch中通过修改form、size参数来控制要返回的分页结果:
GET /indexName/_search
{
"query":{
"match_all":{}
},
"from":990, //分页开始的位置,默认0
"size":10, //期望获取的文档总数,查询结果展示条数
"sort":[
{"price":"asc"}
]
}
深度分页问题
ES是分布式的,所以会面临深度分页问题。例如按price排序,获取from=990,size=10的数据
深度分页解决方案
针对深度分页,ES提供了两种解决方案:
search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式(只能向后翻页不能向前翻页)
scroll:原理将排序数据形成快照,保存在内存。官方已经不推荐使用(内存占用大,且结果非实时)
高亮
高亮就是把搜索结果中把关键字突出显示。
原理:将搜索结果中的关键字用标签标记出来;在页面中给标签添加css样式
GET /indexName/_search
{
"query":{
"match":{"搜索字段":"搜索内容"}
},
"highlight":{
"fields":{
"要高亮的字段":{
"pre_tags":"<em>", //用来标记高亮字段的前置标签
"post_tags":"</em>", //用来标记高亮字段的后置标签
"require_field_match":"false" //默认情况下,ES搜索字段必须与高亮字段一致,才能高亮,如果不一致,需要把这个配置设置为false才能高亮成功
}
}
}
}
数据聚合
聚合的种类
聚合可以实现对文档数据的统计、分析、运算。聚合(聚合字段不能分词)常见的有三类:
通(Bucket)聚合:用来对文档做分组
termAggregation:按照文档字段做分组
Data Histogram:按照日期阶梯分组,例一周为一组
度量(Metric)聚合:用以计算一些数值:
Avg:求平均值
Max:求最大值
Min:求最小值
Stats:同时求Max、Min、avg、sum等
管道(pipeline)聚合:其他聚合的结果为基础做聚合
DSL实现聚合
DSL实现Bucket聚合
Bucket聚合会统计Bucket内的文档数量,记为_count,并且按照_count降序排序
默认情况下,Bucket聚合是对索引库的所有文档做聚合,我们可以限定要聚合的文档范围,只要添加query条件即可
GET /indexName/_search
{
"query":{ //通过添加查询条件从而限定聚合文档范围
"match":{"搜索字段":"搜索内容"}
}
"size":0, //设置size为0,结果中不包含文档,只包含聚合结果
"aggs":{ //定义聚合
"聚合名字":{
"terms":{ //聚合的类型,按照字符串聚合,用term
"field":"参与聚合的字段", //field指定聚合字段
"size":10, //期望获取的聚合结果数量,控制显示结果数量
"order":{"_count":"asc"} //默认降序排序,此处修改排序为升序
}
}
}
}
DSL实现Metrics聚合
GET /indexName/_search
{
"size":0
"aggs":{
"聚合名字1":{
"terms":{
"field":"参与聚合的字段",
"size":10,
"order":{"聚合名称2.avg":"asc"} //实现子聚合排序
},
"aggs":{ //是聚合1的子聚合,也就是分组后对每组分别计算
"聚合名称2":{
"stats":{ //聚合类型,这里stats可以计算min\max\avg等
"field":"参与聚合的字段"
}
}
}
}
}
}
自动补全
拼音分词器
自定义分词器
我们在创建索引库时,通过setting来配置自定义的analyzer(分词器):
拼音分词器适合在创建倒排索引的时候使用,但不能在搜索的时候使用。
PUT /索引库名
{
"settings":{
"analysis":{
"analyzer":{ //自定义分词器
“自定义分词器的名字”:{
“tokenizer”:"ik_max_word", //先分词
"filter":"pinyin" //再把分好的词转成拼音
}
}
}
}
}
DSL实现自动补全查询
completion suggester查询语法:
//自动补全查询
GET /indexName/_search
{
"suggest":{
"title_suggest":{
"text":"s", //关键字
"completion":{
"field":"补全查询的字段"
"skip_duplicates":true, //跳过重复的
"size":10 //展示前10条数据
}
}
}
}
数据同步
数据同步思路分析
elasticsearch中的酒店数据来自MySQL数据库,因此MySQL数据发生改变时,elasticsearch也必须跟着改变,这个就是elasticsearch与MySQL之间的数据同步。
“MQ” 是 “Message Queue”(消息队列)的缩写。消息队列是一种跨进程或跨服务器通信的技术,它允许不同的应用组件通过发送和接收消息来进行异步通信。这种机制非常适合用于实现数据库与搜索引擎之间的数据同步。
在实现 MySQL 到 Elasticsearch 的数据同步过程中,通常会利用数据库的变更数据捕获(CDC)技术来监控数据的变化,并将这些变化作为消息发送到消息队列中,然后由专门的服务从消息队列中读取消息并更新到 Elasticsearch 中。这样做的好处是可以保证数据的一致性和完整性,同时提高系统的可靠性和性能。
MySQL的binlog(Binary Log)是MySQL数据库的一种二进制日志文件,它记录了数据库的所有更改操作(如INSERT、UPDATE、DELETE等),但不包括SELECT查询。Binlog的主要用途包括数据恢复、主从复制以及审计等
binlog是MySQL数据库维护和高可用性的重要工具之一,对于保证数据安全、实现数据复制等功能至关重要。特别是在涉及到MySQL到Elasticsearch的数据同步场景中,利用binlog捕获MySQL的数据变化,并通过合适的方式(如借助消息队列)将这些变化同步到Elasticsearch中是非常常见的做法。
Canal是由阿里巴巴开源的一个用于MySQL数据库增量数据订阅和消费的组件。它允许开发者捕获MySQL binlog日志中的变化(如INSERT、UPDATE、DELETE操作),并将这些变更同步到其他存储系统中,比如Elasticsearch、HBase或其他MySQL实例等。Canal的主要应用场景包括数据同步、实时数据分析、缓存更新等。
实现elasticsearch与数据库数据同步
ES集群了解
单机的elasticsearch做数据存储,必然面临两个问题:海量数据存储问题、单点故障问题
海量数据存储问题:将索引库从逻辑上拆分为N个分片(shard),存储到多个节点
单点故障问题:将分片数据在不同节点备份(replica)
ES集群的分布式存储