分布式搜索引擎-ES
一、文档乐观锁控制
1.版本7.2以前
版本7.2以前ES根据version来做乐观锁控制
(1) 更新文档的部分数据
格式:post请求 – http://192.168.43.8:9200/索引库名称/_doc/文档id?version=版本号
请求体中数据:
{
"doc": {
"name": "study-2",
"desc": "study is very good, 学习非常优秀!!"
}
}
(2) 更新文档的所有数据
格式:post请求 – http://192.168.43.8:9200/索引库名称/_doc/文档id?version=版本号
请求体中数据:
{
"name": "study-2",
"desc": "study is very good, 学习非常优秀!!"
...文档的所有字段
}
2.版本7.2以后
版本7.2以后ES根据seq_no 和 primary_term 来做乐观锁控制
seq_no 相当于学号
primary_term相当于班级
每次更新seq_no都会累加,初始值为1
(1) 更新文档的部分数据
格式:post请求 – http://192.168.43.8:9200/索引库名称/_doc/文档id?if_seq_no=对应序列号&if_primary_term=对应值
请求体中数据:
{
"doc": {
"name": "study-2",
"desc": "study is very good, 学习非常优秀!!"
}
}
(2) 更新文档的所有数据
格式:post请求 – http://192.168.43.8:9200/索引库名称/_doc/文档id?if_seq_no=对应序列号&if_primary_term=对应值
请求体中数据:
{
"name": "study-2",
"desc": "study is very good, 学习非常优秀!!"
...文档的所有字段
}
二、分词与内置分词器
默认分词器只支持英文
请求方式
post请求:http://192.168.43.8:9200/_analyze
请求体数据为:
{
"analyzer":"standard",
"text":"I Study in every day"
}
分词结果:i、 study、 in、 every、 day
大写会默认转换为小写
5种内置分词器
1.standard:标准分词器(默认),特点——>会将所有单词分解出来,并且字母默认转换为小写;
2.simple:按照非字母进行差分,例如don’t会拆分为 don t,同样字母默认转换为小写;
3.whitespace:按空格进行切分,例如 I study in,every day not don’t 将会被分解为 i、 study、 in, every、 day、 not 、don’t ,注意in, every被分解为了一个单词;
4.stop:正常分解,但是会去掉语句中的冠词,例如 I study in the every day 将会被分解为 i、 study、 every 、day;
5.keyword:一整段会被认为是一个单词,不会进行任何才分;
三、ik分词器插件
安装包:https://github.com/medcl/elasticsearch-analysis-ik/releases
源码:https://github.com/medcl/elasticsearch-analysis-ik
1.安装
(1)上传elasticsearch-analysis-ik-7.4.2.zip 到服务器
(2)通过unzip解压文件(unzip elasticsearch-analysis-ik-7.4.2.zip -d /usr/local/elasticsearch-7.4.2/plugins/ik)
(3)elasticsearch服务
2.分词器
ik_max_word:只要是单词就会分解,分解细粒度较小
ik_smart:分解语句时细粒度较小
3.自定义中文词库
(1)修改配置文件
IKAnalyzer.cfg.xml 文件所在位置, 一般在es安装目录下 conf/analysis-ik/config/IKAnalyzer.cfg.xml 或者在es安装目录下plugins/elasticsearch-analysis-ik-*/config/IKAnalyzer.cfg.xml
文件内容如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">custom/ext_stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<entry key="remote_ext_dict">location</entry>
<!--用户可以在这里配置远程扩展停止词字典-->
<entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>
</properties>
修改<entry key="ext_dict">自定义词库所在的本地路径</entry>
重启es服务即可生效
详情参见:https://github.com/medcl/elasticsearch-analysis-ik
四、DEL搜索
1.入门语法
(1)基于路径构建请求(QueryString)
get请求:http://192.168.43.8:9200/索引库名称/_search?q=字段名1:搜索内容1&q=字段名2:搜索内容2
(2)结构化查询(DSL)
post请求 http://192.168.1.6:9200/索引库名称/_doc/_search
请求体内容:
{
"query":{
"match":{
"字段名":"学习"
}
}
}
判断某个字段是否存在,代码如下:
{
"query":{
"exists":{
"field":"字段名"
}
}
}
2.查询所有与分页
(1)基于路径构建请求–查询所有(QueryString)
get请求:http://192.168.1.6:9200/索引库名称/_doc/_search
(2)结构化查询(DSL)
post请求 http://192.168.1.6:9200/索引库名称/_doc/_search
请求体内容:
{
"query":{
"match_all":{}
}
}
返回字段筛选,如下,只返回id和username
{
"query":{
"match_all":{}
},
"_source":[
"id",
"username"
]
}
分页:
{
"query":{
"match_all":{}
},
"from": 起始位置,
"size": 条数
}
3. term与match
term(关键字不会被分词):
{
"query":{
"term":{
"字段名":"关键字"
}
}
}
terms(关键字不会被分词):
{
"query":{
"terms":{
"字段名":["关键字1","关键字2","关键字3"]
}
}
}
4. match_phrase
{
"query":{
"match_phrase":{
"字段名":{
"query": "关键字1 关键字2",
"slop": slop默认为0,为0,表示关键字1和关键字2必须连贯,为1时表示关键字1和关键字2中间可隔1个词,以此类推
}
}
}
}
其他如:
{
"query":{
"match_phrase":{
"字段名":{
"query": "网站 学习 到了",
"slop":10
}
}
}
}
4. match(operator)与ids
operator 关键字:
{
"query":{
"match":{
"字段名":{
"query": "搜索内容",
"operator":"and"
}
}
}
}
上述关键字"operator"如果为or的话,表明结果只要匹配搜索内容分词后的其中一条即可;
"operator"如果为or的话,表明结果需要匹配搜索内容分词后的所有关键字;
minimum_should_match 关键字:
{
"query":{
"match":{
"字段名":{
"query": "搜索内容",
"minimum_should_match":"60%"
}
}
}
}
上述关键字"minimum_should_match"如果为x%的话,表明结果至少包含搜索内容分词后的x%个单词;
"minimum_should_match"如果为数字n的话,表明结果至少需要包含搜索内容分词后的n个单词;
ids 关键字:
{
"query":{
"ids":{
"type": "_doc",
"values":["id1","id2"]
}
}
}
5.multi_match与boost
以多个字段作为搜索对象(按默认权重排序,倒叙)
{
"query":{
"multi_match":{
"query": "搜索内容",
"fields":["字段1","字段2"]
}
}
}
以多个字段作为搜索对象(按指定权重排序,倒叙)
{
"query":{
"multi_match":{
"query": "搜索内容",
"fields":["字段1^权重1","字段2^权重2"]
}
}
}
6.布尔查询
(1)关键字 must
{
"query": {
"bool": {
"must": [
{
"term": {
"字段1": "搜索内容"
}
},
{
"term": {
"字段2": "搜索内容"
}
}
]
}
}
}
上述条件,必须满足关键字"must"中的每一个条件
(2)关键字 should
{
"query": {
"bool": {
"should": [
{
"term": {
"字段1": "搜索内容"
}
},
{
"term": {
"字段2": "搜索内容"
}
}
]
}
}
}
上述条件,只要满足关键字"should"中的任意一个条件即可
(3)关键字 must_not
{
"query": {
"bool": {
"must_not": [
{
"term": {
"字段1": "搜索内容"
}
},
{
"term": {
"字段2": "搜索内容"
}
}
]
}
}
}
上述条件,不满足关键字"must_not"中的所有
(4)关键字 must,must_not,should联用
{
"query": {
"bool": {
"must": [
{
"term": {
"字段1": "搜索内容"
}
},
{
"term": {
"字段2": "搜索内容"
}
}
],
"must_not": [
{
"term": {
"字段3": "搜索内容"
}
}
],
"should": [
{
"term": {
"字段4": "搜索内容"
}
}
]
}
}
}
上述内容,表示必须满足must的条件,并且不包含must_not中条件,或者在此基础上满足should中的任一条件
(4)关键字 boost(加权)
{
"query": {
"bool": {
"must": [
{
"match": {
"字段名1": {
"query":"大家的环境",
"boost":10
}
}
},
{
"term": {
"字段名2": "0"
}
}
]
}
}
}
7.过滤器
{
"query": {
"match":{
"字段名1":"搜索内容"
}
},
"post_filter":{
"range":{
"字段名2":{
"gte":66, #指大于等于66
"lt":1000 #小于1000
}
}
}
}
gt:大于(greater than)
lt:小于(less than)
gte:大于等于(greater than equals)
lts:小于等于(less than equals)
8.排序
{
"query": {
"match":{
"字段名":"搜索内容"
}
},
"sort":[
{
"字段名1":"asc"
},
{
"字段名2":"desc"
}
]
}
asc:升序
desc:降序
9.高亮-highLight
{
"query":{
"match":{
"字段名":"搜索内容"
}
},
"highlight":{
"pre_tags":["<span>"],
"post_tags":["</span>"],
"fields":{
"字段名":{}
}
}
}
pre_tags:前缀,post_tags:后缀,包裹分词后的搜索内容,用以高亮显示;也可以不用这两个关键字,不用则以<em></em>
包裹
五、进阶操作
1.深度分页
(1)概念
ES搜索数据范围过广(一般from的值过大)时,称之为深度分页;搜索数据超过10000条时,会报错(illegal_argument_exception)。
(2)语法
post请求,http://192.168.1.6:9200/索引库名称/_doc/_search
{
"query":{
"match_all":{
}
},
"from": 9999,
"size":10
}
如上,我们在获取9999至10009区间的数据时,实际上每个分片拿到的是10009条,然后将每个分片获取到的数据合并,合并之后再排序,最终会获得最后的10条数据。这样的话,搜索太深,性能影响很大,一般情况而言,我们会避免深度分页操作,限制分页页数。
(3)查询ES深度搜索限制
get请求 http://192.168.1.6:9200/shop/_settings
(4)修改ES深度搜索限制
put请求 http://192.168.1.6:9200/索引名称/_settings
请求体中参数
{
"index.max_result_window":限制条数
}
2.滚动搜索
第一步:初始化查询
post 请求 http://192.168.1.6:9200/索引库名/_search?scroll=1m
参数scroll 表示滚动查询会话保持时间
请求体:
{
"query":{
"match_all":{
}
},
"sort": "_doc",
"size":10
}
sort:表示操作类型,"sort": "_doc"
表示文档操作
size:表示每页大小
第二步:批量获取
post 请求 http://192.168.1.6:9200/_search/scroll
{
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAJ9Fm13STJuYW0tVDd5SjdoNjY2aGpHdUEAAAAAAAACgRZtd0kybmFtLVQ3eUo3aDY2NmhqR3VBAAAAAAAAAn4WbXdJMm5hbS1UN3lKN2g2NjZoakd1QQAAAAAAAAJ_Fm13STJuYW0tVDd5SjdoNjY2aGpHdUEAAAAAAAACgBZtd0kybmFtLVQ3eUo3aDY2NmhqR3VB",
"scroll":"1m"
}
scroll_id :指上次请求返回的结果_scroll_id,当没有结果返回时,就意味着批次处理完毕;
scroll:滚动查询会话保存时间
注意:尽管我们每次查询指定size为某个值,如1000,但实际上我们可能取到超过这个值的文档,当查询时,size作用于每个单分片,所以每个批次实际返回的文档数量最大为size*number_of_primary_shards。
3.批量查询
post请求 http://192.168.1.6:9200/索引库名称/_doc/_mget
请求体:
{
"ids":["1001","1005"]
}
mget与search
用search查多个:
post请求 http://192.168.1.6:9200/索引库名称/_doc/_search
{
"query":{
"ids":{
"type":"_doc",
"values":["1001","1005"]
}
}
}
他们之间除了查询方式迥异,返回结果也有所差异,感兴趣的话,可以自行测试。
4.批量操作
(1)bulk-create
post请求 http://192.168.1.6:9200/_bulk
{"create":{"_index":"索引库名称","_type":"_doc","_id":"2004"}}
{"id":"2004","nickname":"name-2004"}
{"create":{"_index":"索引库名称","_type":"_doc","_id":"2005"}}
{"id":"2005","nickname":"name-2005"}
{"create":{"_index":"索引库名称","_type":"_doc","_id":"2003"}}
{"id":"2003","nickname":"name-2003"}
id和nickname都是文档中的字段
注意:请求体需要以换行(\r\n)结尾
请求体中的_index参数和_type参数也可以直接放在路径上(http://192.168.1.6:9200/索引库名称/_doc/_bulk),如果这两个参数放在路径上,请求体中就不需要再写这两个参数了,下面介绍index时,会使用到这种格式
(2)bulk-index
post请求 http://192.168.1.6:9200/shop2/_doc/_bulk
{"index":{"_id":"2004"}}
{"id":"2004","nickname":"index-2004"}
{"index":{"_id":"2007"}}
{"id":"2007","nickname":"name-2007"}
{"index":{"_id":"2008"}}
{"id":"2008","nickname":"name-2008"}
index和create的区别在于,index是没有这条数据就创建,有就覆盖;create时没有就创建,有就失败(只失败这一条,其他正常创建)。
(3)bulk-update、delete
update
post请求 http://192.168.1.6:9200/shop2/_doc/_bulk
{"update":{"_id":"2004"}}
{"doc":{"id":"3306"}}
{"update":{"_id":"2016"}}
{"doc":{"id":"2016","name":"name-2016"}}
delete
post请求 http://192.168.1.6:9200/shop2/_doc/_bulk
{"delete":{"_id":"2009"}}
{"delete":{"_id":"2018"}}
注意:这几种操作是可以放在一次请求里的。