目录
一、初始elasticsearch
1、概述
简介
发展
2、倒排索引
3、基本概念
文档
索引
Mysql和es的区别
4、分词器
初始分词器
Ik分词器-扩展词库
二、索引库操作
1、mapper属性
2、创建索引库
3、查询、删除索引库
三、文档操作
1、新增文档
2、查询、删除文档
3、修改文档
四、RestClient
1、什么是RestClient
2、JavaRestClient
建立mapping映射
初始化JavaRestClient
创建索引库
操作索引库
操作文档
五、DSL查询文档
1、DSL查询语法
查询所有
全文检索查询
精确查询
地理查询
复合查询
2、搜索结果处理
排序
分页
高亮
3、RestClient
一、初始elasticsearch
1、概述
简介
es是一款强大的开源搜索引擎,开源帮助我们从海量数据中快速找到需要的内容
elasticsearch是elastic stack(ELK)包含Kibana、Logstash、Beats
发展
Lucene
Lucene是java语言的搜索引擎类库,apache公司顶级项目,1999年研发
优点易扩展,高性能(基于倒排索引),缺点只限于java语言,学习曲线陡峭,不支持水平扩展
Compass
2004是由shay banon基于Lucene开发的
elasticsearch
2010年Shay banon重写了Compass并取名为elasticsearch
比lucene的优点:支持分布式,可水平扩展。提供restful,可被任何语言调用
2、倒排索引
传统的正向索引:例如下面的图,会去从1开始一条条模糊匹配任何匹配的放到结果集返回了,如果有1000万条数据,就要扫描1000万次
倒排索引:
文档(document):每个商品就是文档,
词条(term):文档按照语义分成的词语
就是把词语先分词提前存好,每个词语对应的id,当我们要搜索的时候就通过词语拿到所有匹配的id来返回,这种方式的效率就比原本正向的高很多。
适用场景:更适合基于文档去搜索内容,比如搜索异常信息和局部的单词搜索等等。
3、基本概念
文档
es是面向文档存储的,可以是数据库中的一条商品数据,一个订单信息
文档数据会被序列化为json格式后存储在es中
索引
相同类型的文档的集合
映射mapping:索引中文档的字段约束信息,类似表的结构约束
Mysql和es的区别
mysql擅长事务类型操作,可以保证数据安全和一致
es擅长海量数据的搜索、分析、计算
4、分词器
初始分词器
es在创建倒排索引时需要对文档分词,在搜索时,需要对用户输入内容分词,但默认分词规则对中文处理不好,中文会被分成一个个的字
处理中文分词,一般用IK分词器
安装IK分词器:找到数据局目录,然后把安装好的ik分词器,解压分词器安装包,放到es容器的插件数据卷中,重启容器。
ik_smart:粗力度划分,分的词语不够多但是占用内存小
ik_max_word:细粒度划分,分的词语多匹配更加多,但是内存大
Ik分词器-扩展词库
我们发现很多词语是没有的,不会自动分词,比如一些新的网络词汇,要扩展ik分词器,只需要修改ik分词器目录中config目录中的ikAnalyzer.cfg.xml文件,然后在里面写上文件
不仅仅可以扩展,还可以禁止一些词语,比如分的时候“的”字就是没有意义还占用内存,还有紧张搜索的敏感词汇也可以禁止了
二、索引库操作
1、mapper属性
mapping是对索引库中文档的约束,常见的mapping属性包括:
type:字段数据类型,常见的简单类型有:
- 字符串:text(可分词的文本)、keyword(精确值,最小不能拆分的:国家、品牌、IP地址)
- 数值:long、integer、short、byte、double、float
- 布尔:boolean
- 日期:date
- 对象:Object
(在es里面是没有数组这个概念的,可以有很多个同类型的数值)
index:是否创建索引,默认为true,如果true就会创建倒排索引,将来就能搜索了,实际上并不是所有字段都需要参与搜索的,所以要手动把一些设置成false
analyzer:使用那种分词器,结合字符串的text来使用的
properties:该字段的子字段(可以指定对象的子属性)
2、创建索引库
ES中通过restful请求操作索引库、文档。请求内容用DSL语句来表示,创建索引库和mapping的DSL语句如下:
3、查询、删除索引库
查询用get,删除用delete,修改用put(es没有办法修改的其实,因为每次修改要查询维护倒排索引库非常麻烦,所以修改其实是在原本的索引库里面添加新字段)
三、文档操作
1、新增文档
新增文档的DSL语法
2、查询、删除文档
3、修改文档
全量修改,请求方式是put,既能做修改,也能做新增,当id没有的时候就代表新增了,他是先删除逐个id然后再新增的,如果id没有就直接增了
指定修改,就是修改指定的值,请求方式是post,中间的路径得改成_update
四、RestClient
1、什么是RestClient
ES官方提供了各种语言的客户端,用来操作es,这些客户端用来组装DSL语句,通过HTTP请求发送给ES
2、JavaRestClient
建立mapping映射
先根据数据库的表建立对应es的mapping
在es里面经纬度比较特殊,要用geo_point
需求:现在想要根据多个字段来搜索,但是多个搜索没有根据一个来搜性能好?怎么办?
es提供了组合查询,类似联合索引的概念,可以单独提出一个字段叫all,把想加进去的属性加上copy_to:all
提示:字段拷贝可以使用copy_to属性将当前字段拷贝到指定字段
初始化JavaRestClient
@BeforeEach是在测试方法@Test前执行,@AfterEach是在测试方法后执行,都是junit的注解
创建索引库
常量里面直接写json对象就行
操作索引库
索引库操作的基本步骤:
- 初始化RestHighLevelClient
- 创建XxxlndexRequest。XXX是CREATE、Get、Delete
- 准备DSL (CREATE时需要)
- 发送请求。调用RestHighLevelClient#indices().xxx()方法,xxx是create、exists、delete
操作文档
新增
要用过fastJson工具类把对象序列化为json对象存到es
查询
修改
删除
批量导入
文档操作的基本步骤
- 初始化RestHighLevelClient
- 创建XxxRequest。XXX是Index、Get、Update、Delete
- 准备参数 (index和Update时需要)
- 发送请求。调用RestHighLevelClient#xxx0方法,xxx是
- index、get、update、delete
- 解析结果(Get时需要)
五、DSL查询文档
1、DSL查询语法
DSL是基于restful风格的查询语句,用来查询es的
查询语句分类:
- 查询所有:查询出所有数据,一般测试用。例如:match all
- 全文检索 (fulltext)查询: 利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:
- match query
- multi_match query
- 精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。例如:
- ids
- range
- term
- 地理(geo)查询: 根据经纬度查询。例如:
- geo distance
- geo_bounding_box
- 复合(compound)查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。例如
- bool
- function_score
查询所有
由于查询所有并不需要指定条件,所以条件值不用写
全文检索查询
我们搜索的时候尽量使用match搜一个字段,然后用all就可以把多个属性放到一个字段来搜索,这样效率比直接搜多个字段快
- match:根据一个字段查询
- multi match:根据多个字段查询,参与查询字段越多,查询性能越差
精确查询
精确查询一般查询keyword、数值、日期、boolean等类型字段,所以不会对搜索条件进行分词。
- term:根据词条精确匹配,一般搜索keyword类型、数值类型、布尔类型、日期类型字段
- range: 根据数值范围查询,可以是数值、日期的范围
地理查询
根据经纬度查询,官方文档,例如:
geo_bounding_box:适合查询一定范围内所有的信息。
geo_distance:查询到指定中心店小于某个距离值的所有文档,适合做附近的人
复合查询
复合查询:复合查询可以将其他简单查询组合起来,实现更复杂的搜索逻辑
fuction score:算分函数查询,可以控制文档相关性算法,控制文档排名
es中相关打分算法:
TF-IDF:es5.0之前,会虽则词频增大而越来越大
BM25:在es5.0之后,词频增大,但增长曲线会趋于水平
Function Score Query
Boolean Query
布尔查询是一个或多个查询子句的组合,子查询的组合方式有:
must:必须匹配每个子查询,类似与
should:选择性匹配子查询,类似或
must_not:必须不匹配,不参与算分,类似非
filter:必须匹配,不参与算分
下面这些就固定的不参与算分,可以提高搜索效率,而且这种不参与算分的往往会放到缓存里,进一步提高效率,参与算分条件越多,查询的性能越差
图中:must_not来查询价格,小于500的,就是要查实际上大于500的,之所以用这个反着查就是为了提高效率,因为不用参与算法,而且这个价格的权重也不重要,所有这样效率最高,项目filter搜分大于45也是如此,关键词才需要参与算分的,不参与算分全部放到must_not和filter里面
2、搜索结果处理
排序
es支持对结果进行排序,默认是根据分值排序,可以排序的字段类型:keyword类型、数值类型、地理坐标类型、日期类型等
分页
es默认情况只返回top10的数据,而如果要查询更多数据就需要修改分页参数了
es中通过from、size参数来控制要返回的分页结果:
ES是分布式的,所有会面临深度分页问题,例如按price排序后,获取from=990,size为10的数据
深度分页解决方案
针对深度分页,es提供两种解决方案
search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式
scroll:原理将排序数据形成快照,保存在内存,官方已经不推荐使用。(内存消费非常大,而且将来es一更新快照还是旧的数据)
高亮
如图我们可以观察到,搜索出来的结果会高亮,其实加了标签,是谁加的呢?其实是es服务端加的,他给关键字加了标签,然后返回给前端。
require_field_match为false代表搜索的属性不一定要匹配,用all来搜可以高亮name的
3、RestClient
搜索全部
解析对象
全文检索查询
精确查询
boolean查询
排序和分页
高亮
先看看请求的DSL构建
高亮结果处理
总结
所有的DSL构建,都是用SearchRequest的source()方法