ElasticSearch:介绍

先放官方中文网站镇楼:
https://www.elastic.co/cn/

按照本文的流程去学习,保证一定有收获。如果暂时没时间学,不妨点个收藏点个赞,找个时间慢慢学。那么我们接下来就开始ES的旅程吧!

首先,ElasticSearch是什么?

ElasticSearch是基于RESTful web接口的全文搜索引擎 ,简单说就是可以对存储的数据进行快速搜索的强大引擎。

MySQL同样可以存储数据,为什么一定要用ES?

mysql存储用作持久化存储,而ES的存储用作检索分析

ElasticSearch中的各种名词

1. index索引
动词:相当于mysql的insert
名词:相当于mysql的db2. Type类型
在index中,可以定义一个或多个类型
类似于mysql的table,每一种类型的数据放在一起3. Document文档
保存在某个index下,某种type的一个数据document,文档是json格式的,
document就像是mysql中的某个table里面的内容。每一行对应的列叫属性其中index库 > type表 > document文档

为什么ES搜索快?

因为ES使用了倒排索引。

什么是倒排索引?

举个例子:ES对存入数据进行分词存储,比如红海行动,存储为红海、行动。探索红海行动存储为探索、红海、行动。用户搜索红海,则对红海进行索引搜索,搜索出红海行动,探索红海行动。

ElasticSearch:安装

基本介绍完毕,接下来我们来学学如何安装ES和Kibana,ES和kibana的关系可以看成是好基友的关系,kibana可以更方便地操作ES。

这里使用的是docker进行安装,方便,快捷,好使。

使用docker进行安装:

1、下载ElasticSearch(存储检索)和Kibana(可视化检索),两个版本要一致

docker pull elasticsearch:7.4.2
docker pull kibana:7.4.2

2、配置

#docker里的目录挂载到linux的/mydata目录中
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data#es可以被远程任何机器访问
echo "http.host: 0.0.0.0" >/mydata/elasticsearch/config/elasticsearch.yml#更改权限
chmod -R 777 /mydata/elasticsearch/

3、启动ElasticSearch

#9200是用户交互端口 9300是集群心跳端口
#-e指定是单阶段运行
#-e指定占用的内存大小,生产时可以设置32G
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e  "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v  /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2 #设置开机启动elasticsearch
docker update elasticsearch --restart=always

访问:

http://xxxx:9200/

4、启动kibana

#kibana指定了了ES交互端口9200  # 5600位kibana主页端口
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://47.97.26.154:9200 -p 5601:5601 -d kibana:7.4.2#设置开机启动kibana
docker update kibana  --restart=always#查看kibana运行日志
docker logs 实例ID

访问5601,出现以下则表示成功:

ElasticSearch:入门使用

安装完成了,那我们来试试ES好不好使。

我们对ES的所有操作,都被封装成了RestAPI,所以我们只要发送请求就行了。

入门:

1、_cat

功能:查看ES的基本信息
使用postman或者浏览器加上地址查询,或者直接Kibana操作。

GET _cat/nodes:查看所有结点
GET _cat/health:查看es健康状况
GET _cat/master:查看主节点
GET _cat/indices:查看所有索引[类似于show databases]

2、索引一个文档(保存)

用mysql的话来说,就是保存一条记录
索引到哪个类型下 == 保存到哪张表中
如:

PUT http://xxxx:9200/customer/external/1
JSON:{"name":"john"    }

结果:

{"_index": "customer","_type": "external","_id": "1","_version": 1,"result": "created","_shards": {"total": 2,"successful": 1,"failed": 0},"_seq_no": 0,"_primary_term": 1
}

我们分析下都返回了些什么:

返回结果中,所有带有_的都被称为元数据,用来携带一些基本信息
"_index":"customer":数据存在索引customer下[mysql即哪个数据库下]
"_type": "external":数据存在类型external下[mysql即哪张表下]
"_id": "1":数据ID
"_version": 1:数据版本
"result": "created":执行结果[若执行两遍PUT,则此处变为update]

细节:
保存操作可以使用PUT或者POST,但是经过多次操作可以发现:
使用PUT进行保存数据时,携带ID会创建或者修改数据,不携带ID则报错。
使用POST保存数据时,携带ID会创建或者修改数据,不携带ID则会自动生成一个唯一ID,因此对于保存操作。
虽然PUT和POST请求都可,但是我们一般还是使用POST,可以减少容错,显得更专业。

3、查询文档

拿刚刚的操作举个栗子:

GET http://xxxx:9200/customer/external/1

语句解读:不带任何参数,使用GET对customer索引下的external类型下的id为1的数据进行查询
结果:

{"_index": "customer","_type": "external","_id": "1","_version": 2,"_seq_no": 2,"_primary_term": 1,"found": true,"_source": {"name": "john"}
}

结果分析:

"_index": "customer",索引
"_type": "external",类型
"_id": "1",查询ID
"_version": 2,版本[被更新过几次,下标从1开始]
"_seq_no": 2,乐观锁[稍后说]
"_primary_term": 1,分片,用作乐观锁
"found": true,是否查询成功
"_source":数据查询的信息

我们模拟以下乐观锁操作,可以更有助于理解:
情境:A和B同时需要对同一条数据进行修改,于是两人各自开始操作:
A先查出数据如下:

{"_index": "customer","_type": "external","_id": "1","_version": 2,"_seq_no": 2,"_primary_term": 1,"found": true,"_source": {"name": "john"}
}

A开始修改数据,B来到工位,一查,seq_no也为2,刚准备开始修改数据,突然接到个电话,于是暂停手上工作。
A修改如下:

PUT http://XXXX:9200/customer/external/1?if_seq_no=2&if_primary_term=1
{"name":"yellow"
}

解读:加上了判断条件进行修改
修改结果:

{"_index": "customer","_type": "external","_id": "1","_version": 3,"result": "updated","_shards": {"total": 2,"successful": 1,"failed": 0},"_seq_no": 3,"_primary_term": 1
}

B打完电话,继续工作,由于原先已经查询了,只是还未来得及提交,于是B省得麻烦,直接提交。

PUT http://XXXX:9200/customer/external/1?if_seq_no=2&if_primary_term=1
{"name":"red"
}

结果:

{"error": {"root_cause": [{"type": "version_conflict_engine_exception","reason": "[1]: version conflict, required seqNo [2], primary term [1]. current document has seqNo [3] and primary term [1]","index_uuid": "kIKj5ZSlT32aH-ziXyQN2Q","shard": "0","index": "customer"}],"type": "version_conflict_engine_exception","reason": "[1]: version conflict, required seqNo [2], primary term [1]. current document has seqNo [3] and primary term [1]","index_uuid": "kIKj5ZSlT32aH-ziXyQN2Q","shard": "0","index": "customer"},"status": 409
}

于是B只好重新先查询,再进行修改。
这就是乐观锁修改。

4、更新文档

POST customer/external/1/_update
{"doc":{"name":"blue"    }
}
或者
POST/PUT customer/external/1
{"name":"blue"
}

各更新操作分析:
第一种更新:
我们继续使用上面的数据,首先对1号数据进行第一种更新操作:

POST customer/external/1/_update
{"doc":{"name":"john"}
}

第一次结果:

"_version": 5,
"result": "updated"

第二次结果:

"_version": 5,
"result": "noop"

分析:使用这种更新操作进行重复更新时,若数据与原先一致,则不进行任何操作。

第二种更新:

POST customer/external/1
{"name":"blue"
}

第一次结果:

"_version": 6,
"result": "updated"

第二次结果:

"_version": 7,
"result": "updated"

分析:
使用第二种更新操作时[即不带update],无论是否重复更新,数据是否一致,都会进行更新,version版本相应增加。因此若使用PUT方式,结果也一致。

5、删除文档&索引

DELETE http://XXXX:9200/customer/external/1

手动[啪的一下],数据没了:

{"_index": "customer","_type": "external","_id": "1","_version": 9,"result": "deleted","_shards": {"total": 2,"successful": 1,"failed": 0},"_seq_no": 10,"_primary_term": 1
}

我们再试试能不能查到:

GET http://XXXX:9200/customer/external/1

结果:

{"_index": "customer","_type": "external","_id": "1","found": false
}

数据可以删除,那类型和索引是否也可以删除,答案是能删,只能删一点点,ES只提供了直接删除索引的操作,并没有提供直接删除类型的操作,但是我们可以将类型下的所有文档清空,也相当于删除了整个类型。

6、bulk批量API

bulk是ES中可以给ES批量导入数据地语法。
如:

POST customer/external/_bulk
{"index":{"_id":"1"}}
{"name":"John"}
{"index":{"id":"2"}}
{"name":"Jane"}

解析:
我们对customer索引下的external类型进行bulk的POST操作,批量index[保存]id为1的name为John和id为2的name为Jane的两条数据,可以看作每两行为一次操作,同样可以delete,get。

我们在postman中进行操作时发现,JSON数据报错,那这会kibana就派上用场了,我们进入kibana,找到Dev Tools:

在kibana中发送请求:

POST /customer/external/_bulk
{"index":{"_id":"1"}}
{"name":"John"}
{"index":{"id":"2"}}
{"name":"Jane"}

结果成功。

接下来我们继续测试批量数据操作,官方为我们准备了一份样本数据:
https://www.elastic.co/guide/cn/kibana/current/tutorial-load-dataset.html
下载莎士比亚,将其中部分使用bulk批量导入
命令:

POST shakespeare/_bulk
{"index":{"_index":"shakespeare","_id":0}}
{"type":"act","line_id":1,"play_name":"Henry IV", "speech_number":"","line_number":"","speaker":"","text_entry":"ACT I"}
.....

结果若无误,OK,我们继续下一步操作。

ElasticSearch:进阶

进阶检索:
ES支持两种基本方式检索:
uri+检索参数检索
通过使用REST request URI 发送搜索参数(uri+检索参数)如:

GET shakespeare/_search?q=*

uri+请求体检索
通过使用REST request body进行发送(uri+请求体)如:

GET shakespeare/_search
{"query": {"match_all": {}},"sort": []
}

分析:
在以后我们可能更多采用第二种方式,因为可操作性更强,处理复杂请求时更得心应手

"query":"查询条件"
"match_all":"匹配所有"
"sort":"排序条件"

我们一个个试试:

uri+检索参数检索

即第一种请求参数方式检索

GET shakespeare/_search?q=*&sort=account_number:asc

分析:

q=* # 查询所有
sort # 排序字段
asc #升序

检索shakespeare下所有信息,包括type和docs

GET shakespeare/_search

查询结果:

{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 500,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "shakespeare","_type" : "account","_id" : "0","_score" : 1.0,"_source" : {"type" : "act","line_id" : 1,"play_name" : "Henry IV","speech_number" : "","line_number" : "","speaker" : "","text_entry" : "ACT I"}},....    ]}
}

结果分析:

"took" – 花费多少ms搜索
"timed_out" – 是否超时
"_shards" – 多少分片被搜索了,以及多少成功/失败的搜索分片
"max_score" –文档相关性最高得分
"hits.total.value" - 多少匹配文档被找到
"hits.sort" - 结果的排序key(列),没有的话按照score排序
"hits._score" - 相关得分 (not applicable when using match_all)

uri+请求体检索

即第二种请求体方式检索

GET shakespeare/_search
{"query": {"match_all": {}},"sort": []
}

结果与上相同。
我们再进行更多测试,比如我们想只显示部分查询数据

GET shakespeare/_search
{"query": {"match_all": {}},"sort": [],"from": 0,"size": 1
}

解析:查出的数据从"from"开始,长度为"size"进行显示,即显示从0开始的1条数据
结果:

{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 500,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "shakespeare","_type" : "account","_id" : "0","_score" : 1.0,"_source" : {"type" : "act","line_id" : 1,"play_name" : "Henry IV","speech_number" : "","line_number" : "","speaker" : "","text_entry" : "ACT I"}}]}
}

继续测试,我们如果只想返回查询到的数据的某一个部分,那么可以用以下操作[上条件不变]:

GET shakespeare/_search
{"query": {"match_all": {}},"sort": [],"from": 0,"size": 1,"_source": ["line_id","line_number"]
}

解析:"_source"作用是对返回数据进行显示,默认是全部显示
结果:

"_source" : {"line_number" : "","line_id" : 1
}

可以看到只返回了我们指定的数据。

match全文检索

先来个简单的match检索[match的属性必须是_source中存在的]:

GET shakespeare/_search
{"query": {"match": {"line_id": "2"}}
}

结果:

"_source" : {"type" : "scene","line_id" : 2,"play_name" : "Henry IV","speech_number" : "","line_number" : "","speaker" : "","text_entry" : "SCENE I. London. The palace."
}

对于属性的match,不仅可以全属性值match,还可以部分属性值match,功能强大,原因我们之后再说。继续举个栗子,我们对某属性的部分值进行检索

GET shakespeare/_search
{"query": {"match": {"text_entry": "London"}}
}

结果[方便起见,只放查询部分结果]:

  "text_entry" : "SCENE I. London. The palace.""text_entry" : "SCENE III. London. The palace.""text_entry" : "SCENE II. London. An apartment of the Princes.""text_entry" : "riding to London with fat purses: I have vizards"

再再再举个栗子,使用match分词进行全文匹配

GET shakespeare/_search
{"query": {"match": {"text_entry": "be of"}}
}

match条件是text_entry属性中存在be of的结果,无论be of是否在一起,是否相连,是否都存在,只要存在其中一个,就被match。
结果:

 "text_entry" : "Of murderous subornation, shall it be,""text_entry" : "Than out of anger can be uttered.""text_entry" : "thieves of the days beauty: let us be Dianas""text_entry" : "The scourge of greatness to be used on it;""text_entry" : "Of my young Harry. O that it could be proved"....

为何ES能做到这么强大?原因是match进行了分词全文匹配,只要包含了匹配值的都会被查询出来,而ES底层维护了一张倒排索引表,以支持全文匹配和最大得分[匹配相似评比分],且查询结果会以最大得分排序。

match_phrase[短语匹配]

短语匹配不同于match的分词匹配,它必须组合在一起才能被match,举个栗子,使用match_phrase进行匹配查询:

GET shakespeare/_search
{"query": {"match_phrase": {"text_entry": "be of"}}
}

结果:

"hits" : [ ]

还是同一时间,同一地点,结果却不同,这就是match_phrase与match的区别

multi_match[多字段匹配]

可以在多个字段中进行match匹配。
举个栗子,我们同时match匹配两个字段:

GET shakespeare/_search
{"query": {"multi_match": {"query": 1,"fields": ["line_number","speech_number"]}}
}

解析:

"query":查询匹配内容
"fields":被查询的属性字段

结果:

"speech_number" : 1,"line_number" : "1.1.1","speech_number" : 1,"line_number" : "1.1.2",...

如果查询的内容是多词,同样满足match分词匹配条件,也会进行分词查询,最后得出最大分数进行排序。

bool[复合查询]

当我们要构造更复杂的查询时可以使用bool复合查询。其查询规格必须全部被满足。
我们举个栗子,使用bool进行复合查询:

GET shakespeare/_search
{"query": {"bool": {"must": [{"match": {"play_name": "Henry"}},{"match": {"speaker": "HENRY"}}],"must_not": [{"match": {"text_entry": "of"}}],"should": [{"match": {"play_name": "Henry"}}]}}
}

分析:

"bool":表示使用bool查询
"must":必须执行
"must_not":必须不被执行
"should":如果满足其中条件,可以加分[即增加最大分数]

结果:

  "play_name" : "Henry IV","speaker" : "PRINCE HENRY","text_entry" : "and unbuttoning thee after supper and sleeping upon"....

结果过滤

filter可以理解为bool查询中的must_not,作为过滤条件存在。
举个栗子,查询属性text_entry中values中存在and after且line_id在 100 - 120之间的数据

GET shakespeare/_search
{"query": {"bool": {"must": [{"match": {"text_entry": "and after"}}],"filter": {"range": {"line_id": {"gte": "100","lte": "120"}}}}}
}

分析:

"filter":过滤条件
"range":区间

结果:

"_score" : 4.313828
"_score" : 1.2873212
"_score" : 1.2208143

可以发现,其相关性得分各不相同。
但是filter在使用过程中,并不会计算相关性得分, 文档是否符合每个“must”或“should”子句中的标准,决定了文档的“相关性得分”。 得分越高,文档越符合搜索条件。
而must_not会影响文档是否包含在结果中, 但不影响文档的评分方式。

term查询

term查询用于查询非文本字段的值
首先我们先进行一段查询,match的keyword查询与match_phrase查询的区别:

GET shakespeare/_search
{"query": {"match": {"text_entry.keyword": "Breathless and faint, leaning upon my sword,"}}
}
GET shakespeare/_search
{"query": {"match_phrase": {"text_entry": "Breathless and faint, leaning upon my sword,"}}
}

结果[相同]:

"_source" : {"type" : "line","line_id" : 361,"play_name" : "Henry IV","speech_number" : 6,"line_number" : "1.3.33","speaker" : "HOTSPUR","text_entry" : "Breathless and faint, leaning upon my sword,"
}

如果将keyword删去最后的逗号,再执行,发现没有结果,而match_phrase结果不变,于是我们可以发现,keyword的整句搜索就是该字段的全部值;而match_phrase则是短语匹配,只要该字段的全部值中包含搜索条件,则匹配成功。

这个作为一个小复习。

回到term,全文检索字段使用match,其它非text字段匹配用term。这是一个规范。

GET shakespeare/_search
{"query": {"term": {"line_id":361}}
}

聚合分析

通常与查询一起使用,查询检索聚合一步到位,十分强大,类似mysql中的groupby等操作,因此也十分重要。
举个栗子,查询大小为10的地址中包含Mill的人的年龄区间分布,并查出其年龄平均值、收入平均值,并且不想看结果:

#分别为包含mill、,平均年龄、
GET bank/_search
{"query": { # 查询出包含mill的"match": {"address": "Mill"}},"aggs": { #基于查询聚合"ageAgg": {  # 聚合的名字,随便起"terms": { # 看值的可能性分布"field": "age","size": 10}},"ageAvg": { "avg": { # 看age值的平均"field": "age"}},"balanceAvg": {"avg": { # 看balance的平均"field": "balance"}}},"size": 0  # 不看详情
}

如上只是单个聚合,子聚合可以在父聚合的条件下继续聚合。使用起来十分强大。
如需详细了解,可移步官网深究。

ElasticSearch:映射

映射简单说就是定义文档如何被存储和检索的。
[以后不推荐使用类型映射,会降低检索效率,一般使用索引映射]。

查看映射:

GET shakespeare/_mapping

如果我们不满意默认的映射规则,可以自定义映射规则,如:

PUT /my_index
{"mappings": {"properties": {"age":{"type": "integer"}}}
}

解析:按上面规定的映射规格,我们以后在my_index索引下存储的数据都以该映射规则存储和检索。

如果我们在创建索引映射时未创建完全,仍想继续在原索引上添加映射,那么可以这样做:

PUT /my_index/_mapping
{"mappings": {"properties": {"name":{"type": "text"}"phone":{"type":"keyword","index":false}}}
}

解析:如上的作用仅为添加映射,不能作为创建新的索引映射或者更新映射。在映射属性上添加index=false则表示不能使用phone来检索数据,在默认清空下index都为true。

更新映射

很遗憾,在ES的语法中,我们对于已经存在的映射字段,不能更新。但是可以通过创建新的索引进行数据迁移达到相同目的。

数据迁移

固定写法:

POST _reindex
{"source":{"index":"old_index[name]"    },"dest":{"index":"new_index[name]"    }
}

ElasticSearch:分词

分词是ES中做全文检索的核心,作用是将一个字符流分成一个个词元[tokens],然后利用各单词的相关性匹配完成检索,举个栗子:“I am a pig”,默认的标准分词器会将其分为"I",“am”,“a”,“pig”,然后再进行全文检索。

分词操作是分词器[tokenizer]完成的。默认我们使用的是标准分词器。举个栗子:

POST _analyze
{"analyzer": "standard","text": "The 2 Brown-Foxes bone."
}

分词结果:

{"tokens" : [{"token" : "the","start_offset" : 0,"end_offset" : 3,"type" : "<ALPHANUM>","position" : 0},{"token" : "2","start_offset" : 4,"end_offset" : 5,"type" : "<NUM>","position" : 1},{"token" : "brown","start_offset" : 6,"end_offset" : 11,"type" : "<ALPHANUM>","position" : 2},{"token" : "foxes","start_offset" : 12,"end_offset" : 17,"type" : "<ALPHANUM>","position" : 3},{"token" : "bone","start_offset" : 18,"end_offset" : 22,"type" : "<ALPHANUM>","position" : 4}]
}

可以看出标准分词器使用了空格作为标准之一进行了分词。

但是如果我们使用中文进行分词,会发现,每一个中文词都被分割了,而不是我们平常使用的按照词义分词,因此我们需要引入其它分词器。

一般而言,中文大都使用ik分词器:github
注意分词器要和ES版本对应

在前面安装的elasticsearch时,我们已经将elasticsearch容器的“/usr/share/elasticsearch/plugins”目录,映射到宿主机的“ /mydata/elasticsearch/plugins”目录下,所以比较方便的做法就是下载“/elasticsearch-analysis-ik-7.4.2.zip”文件,然后解压到该文件夹下即可。安装完毕后,需要重启elasticsearch容器。

这里操作其实还是推荐使用xftp软件,就一个字,方便。

进入映射目录:cd /mydata/elasticsearch/plugins
下载:wget 下载地址
解压:unzip xxx.zip /ik
卸磨杀驴:rm -rf *.zip
重启ES:docker restart xxxx

成功后,我们试试新的分词器[带有两种中文分词器,分别是ik_smartik_max_work]:

POST _analyze
{"analyzer": "ik_smart","text": "我是中国人"
}

结果:

{"tokens" : [{"token" : "我","start_offset" : 0,"end_offset" : 1,"type" : "CN_CHAR","position" : 0},{"token" : "是","start_offset" : 1,"end_offset" : 2,"type" : "CN_CHAR","position" : 1},{"token" : "中国人","start_offset" : 2,"end_offset" : 5,"type" : "CN_WORD","position" : 2}]
}

OK,到这里分词功能大功告成。

不过有些时候其自带库不能满足我们的需求【流行语等等…】,所以接下来我们来试试自定扩展词库

这里我们使用nginx来实现自定义扩展词库方便点,如果没有nginx,先使用docker安装nginx:

docker run -p 80:80 --name nginx -d nginx:1.10

然后我们需要将容器中的配置文件拷贝到mydata目录下【记得先创建一个nginx文件夹,同时使用命令时结尾的.和空格需要相同】:

docker container cp nginx:/etc/nginx .

然后把容器中的nginx停掉并rm。
我们想将该文件夹中的内容移入nginx的conf文件夹中,因此我们来修改一下,先给nginx文件夹改个名:

mv nginx conf

然后再创建一个nginx文件夹:

mkdir nginx

把conf移入nginx:

mv conf nginx/

创建一个新的nginx,并执行以下命令【挂载】:

docker run -p 80:80 --name nginx \
-v /mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx \
-v /mydata/nginx/conf:/etc/nginx \
-d nginx:1.10

创建成功后,在nginx的conf目录下,我们可以看到三个文件夹,进入html文件夹中,创建一个es文件夹,用来存放我们自定义的词库:

cd mydata/nginx/html
mkdir es
cd es/
vi mycode.txt

nginx方面基本完成,接下来我们来到ES配置远程词库地址:
由于ES也是挂载了文件,因此我们找到ES中配置远程词库文件对应的Linux中的文件中:

cd mydata/elasticsearch/plugins/ik/config/
vi IKAnalyzer.cfg.xml

在这里进行远程词库配置:

<!--用户可以在这里配置远程扩展字典 -->
<entry key="remote_ext_dict">http://XXX/es/mycode.txt</entry>

重启ES:

docker restart XXXX

试试效果,我在自定义中配置了"沙琪玛"和"好吃点":

POST _analyze
{"analyzer": "ik_smart","text": "我爱沙琪玛"
}

结果:

{"tokens" : [{"token" : "我","start_offset" : 0,"end_offset" : 1,"type" : "CN_CHAR","position" : 0},{"token" : "爱","start_offset" : 1,"end_offset" : 2,"type" : "CN_CHAR","position" : 1},{"token" : "沙琪玛","start_offset" : 2,"end_offset" : 5,"type" : "CN_WORD","position" : 2}]
}

成功!
至此基本的ES操作就结束了,如果想要更深入的学习ES,可以去官网查阅相关资料。

祝 进大厂,无996。886,陌生人。

万字长文,学会ElasticSearch,这一篇就够了!相关推荐

  1. 学会JavaScript这一篇就够了~

    文章目录 [One] JavaScript语言基础 一.数据类型 1.数值型 2.字符串型 3.布尔型 二.常量和变量 1.常量 2.变量--例子:输出球员的信息 三.运算符 1.算术运算符--例子: ...

  2. 《万字长文》-吃透Docker-基础篇

    文章目录 1 Docker概述 1.1 Docker诞生背景 1.2 Docker诞生了 1.3 Docker设计理念 1.4 Docker技术理念 2 Docker安装 3 Docker架构 4 测 ...

  3. 《万字长文》-吃透Docker-进阶篇

    文章目录 1 Docker镜像原理 1.1 联合文件系统 1.2 镜像加载原理 1.3 镜像分层结构原理剖析 1.4 从容器创建一个镜像 2 容器数据卷 2.1 使用centos测试 2.2 使用my ...

  4. 四万字!掌握Flink Table一篇就够了

    学习工具与软件版本:开发软件IDEA.Flink1.10.2.Kafka2.0.0.Scala2.11 本章建议有一定Flink基础的伙伴学习 Apache Flink介绍.架构.原理以及实现:点击这 ...

  5. 简单搞懂子网划分,学会子网划分这篇就够了(例题详解)

    为什么要子网划分? 1.满足不同网络对IP地址的需求 2.实现网络的层次化 3.节省IP地址 4.默认子网掩码可以进一步划分,称为可变长子网掩码"VLSM" 有类IP地址规划的缺陷 ...

  6. 【超全汇总】学习数据结构与算法,计算机基础知识,看这篇就够了【ZT帅地】2020-3-7

    https://blog.csdn.net/m0_37907797/article/details/104029002 由于文章有点多,并且发的文章也不是一个系列一个系列发的,不过我的文章大部分都是围 ...

  7. 读论文七步走!CV老司机万字长文:一篇论文需要读4遍

      视学算法报道   编辑:LRS [新智元导读]读论文对于AI新手和工程师来说可能是一件比较难的事.最近一位从业超5年的CV老司机发布了一篇万字长文,讲述了读论文七步法,从找论文到总结,每篇论文由浅 ...

  8. 转载:Vmware 虚拟化 云桌面实操:万字长文,近百张图,完整步骤带你学会Vmware 虚拟化 云桌面

    Vmware 虚拟化 云桌面实操:万字长文,近百张图,完整步骤带你学会Vmware 虚拟化 云桌面 这篇文章对我搭建自己电脑的云桌面雏形很有帮助,转载一下,保存

  9. elasticsearch 客户端工具_万字长文:详解 Spring Boot 中操作 ElasticSearch

    点击上方"小强的进阶之路",选择"星标"公众号 优质文章,及时送达 预计阅读时间: 15分钟 一.ElasticSearch 简介 1.简介 ElasticSe ...

  10. uiautomation遍历windows所有窗口_万字长文!滑动窗口看这篇就够了!

    大家好,我是小浩.今天是小浩算法 "365刷题计划" 滑动窗口系列 - 整合篇.之前给大家讲解过一些滑动窗口的题目,但未作系统整理. 所以我就出了这个整合合集,整合工作中除了保留原 ...

最新文章

  1. Ubuntu连结远程github
  2. 什么是网络推广带你了解新上线的网站该如何提升关键词排名?
  3. 《Linux设备驱动开发详解 A》一一2.3 接口与总线
  4. PostgreSQL在何处处理 sql查询之六十六
  5. php实现socket编程
  6. OpenCV中Kinect的使用(3)
  7. 外网DNS系统外网访问及邮件系统外网域名访问问题
  8. PHP中基本符号及使用方法
  9. 使用try-with-resources优雅的关闭IO流
  10. 【重识 HTML + CSS】CSS 伪类、伪元素
  11. 今天加班做了昨天晚上要写的页面,用到了一些之前用过但还不熟悉需要上网搜索才能用的知识点:...
  12. matlab 计算结果为nan,matlab 计算 结果总是为Nan
  13. 提示框插件toastr
  14. 逐浪海棠居刻本字-第一款基于unicode13标准构建的中文字库全面发布
  15. 怎么批量修改图片尺寸大小?
  16. IcedTea6 1.7.3
  17. 洛谷 P5520 青原樱(组合数学插板法 or 插空法 模板)
  18. win7右键计算机没有注册类,win7系统提示没有注册类别如何解决
  19. 2018 杭州见习报告
  20. 万年历农历程序(抄表法)

热门文章

  1. 如何运用绩效考评结果?
  2. Spring5-Spring的基本配置
  3. ACM-steps--dyx--1.3.4--百步穿杨
  4. Linux小小白入门教程(十):管道命令
  5. win10下如何隐藏Linux盘符,Windows10系统下如何隐藏一个磁盘盘符
  6. 2020年人生态度的转变
  7. 剖析探寻Karmada 云原生多云
  8. 分步教学-使用Python+tkinter开发小学生语文拼音与词组学习机
  9. openlayers 加载geoserver管线并报警闪烁
  10. centos7禁用scp