ElasticSearch
Elastcisearch 是分布式的文档存储。它能以实时的方式存储和检索复杂的数据结构——序列化成为JSON 文档。换句话说,一旦一个文档被存储在 Elasticsearch 中,它就是可以被集群中的任意节点检索到。
尽管现存的 NoSQL 解决方案允许我们以文档的形式存储对象,但是他们仍旧需要我们思考如何查询我们的数据,以及确定哪些字段需要被索引以加快数据检索。在 Elasticsearch 中, 每个字段的所有数据都是默认被索引的 。 即每个字段都有为了快速检索设置的专用倒排索引。而且,不像其他多数的数据库,它能在 同一个查询中 使用所有这些倒排索引,并以惊人的速度返回结果。
ES 的底层是开源库 Lucene,ES 是对 Lucene 的封装,对外提供了REST API的操作接口,外部调用就是向 ES 发送请求即可,做到开箱即用。
注意!!!ES7.x 已经移除 types(类似于 MySQL 中的表)的支持,8.x 将不再支持
注意 kibana、ES、IK 分词插件版本要对应,本文使用版本均为 6.8.4
一、基础概念
1、Index(索引)
动词:相当于 MySQL 中的 insert
名词:相当于 MySQL 中的 database
2、Type(类型)
在 Index(索引中),可以定义一个或多个类型。
类似于 MySQL 中的 Table,每一种类型的数据放在一起
3、Document(文档)
保存在某个索引(Index)下,某种类型(Type)的一个数据(Document)。ES 中每条记录是以 JSON 文档的格式存储的,相当于 MySQL 中的一条记录
4、倒排索引
就是每个分词对应于哪些文档的 id
插入一条记录,就会将该数据进行分词,然后每个分词都有对应一个记录,该记录记下该分词出现在哪些文档中
查询时也会将查询的语句进行分词,然后统计哪些记录命中的分词数多计算相关性得分,返回评分的结果列表。
二、Docker 安装
1、下载镜像文件
docker pull elasticsearch:7.4.2 # 存储和检索数据
docker pull kibana:7.4.2 # 可视化界面:方便可视化检索数据
2、创建 ES 实例
# 将docker中ES容器文件挂在到外部
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data
mkdir -p /mydata/elasticsearch/plugins
chmod -R 777 /mydata
# 将ES配置为可以被远程的任何机器访问
echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
# 9200端口为外面向ES发送REST API端口,9300为ES集群间相互通信端口
# discovery.type=single-node ES以单节点运行
# -Xms64m -Xmx128m 非常重要,不设置初始堆和最大堆的大小,ES会默认抢占所有内存,会造成卡死
# -v 将ES容器的文件关联到外面文件下,实现外面修改容器里面也同时修改,plugins实现以后在外面安装插件重启就可以了
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:6.8.4
# 服务如果没启动,查看启动日志
docker logs -f -t --tail 20 elasticsearch
# 如果是Caused by: java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/nodes
# 则使用以下语句授权
chmod 777 -R /mydata/elasticsearch/
# 自动重启
docker update elasticsearch --restart=always
浏览器访问虚拟机 IP+9200 端口出现以下界面即成功
3、安装 Kibana 实例(可视化界面)
# 这里的ip填写为虚拟机的ip 192.168.2.200,端口为前面ES容器内9200映射到宿主机的端口(前提是虚拟机关闭了防火墙,并且配置了桥接网络)
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.2.200:9200 -p 5601:5601 -d kibana:6.8.4
docker update kibana --restart=always
浏览器访问http://192.168.2.200:5601(这里为虚拟机的ip)
三、ES 实践
ES 是以 REST API 提供服务,外界向接口发送请求即可
下面的地址默认前缀都为http://**192.168.2.200:9200**
1、查看结点信息
- GET /_cat/nodes 查看 ES 集群所有结点信息
- GET /_cat/health 查看 ES 集群健康
- GET /_cat/master 查看 ES 集群的主节点信息
- GET /_cat/indices 查看 ES 集群的所有索引信息(相当于 MySQL 中的 show databases)
2、索引一个文档(保存)
保存一个数据:保存在哪个索引的哪个类型下,指定用哪一个唯一标识,对应的数据以 JSON 形式放置在请求 Body。
请求方法:PUT 或 POST 都可以,PUT 时需要指定唯一标识(否则出错),POST 时可以指定唯一标识也可以不指定(ES 会分配一个唯一标识)
- PUT customer/external/1
{
"name": "John Doe"
}
响应:
{
"_index": "customer", // 索引:对应MySQL中的数据库
"_type": "external", // 类型:对应MySQL中的表
"_id": "1", // 标识
"_version": 1, // 版本号:发送多次则是一个更新操作,版本号会逐渐加1递增
"result": "created", // 结果:第一次发送为created,第二次及以后则是更新updated,与Map相似
"_shards": {
// 分片:集群时会用到
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
保存/更新 | 携带 id | 不携带 id |
---|---|---|
PUT | 必须项,更新保存二合一 | 报错 |
POST | 非必须,更新保存二合一 | 新增操作 |
3、查询数据
GET /customer/external/1
响应:
{
"_index": "customer",
"_type": "external",
"_id": "1",
"_version": 5,
"_seq_no": 5, //并发控制字段,序列号(每次更新自动加1),与_primary_term搭配可以作为乐观锁
"_primary_term": 1, // 主分片,主分片重新分配,如重启,就会变化
"found": true,
"_source": {
// 数据真正内容在_source中
"name": "John Doe"
}
}
更新操作(乐观锁)携带上 ?if_seq_no=#{当前的版本号}&if_primary_term=1
乐观锁(CAS)举例:
例如两个线程多时发起 PUT 操作同一个文档,两个请求都先发起查询,发现当前文档版本号_seq_no 为 5,故同时发起 PUT 请求,仅在版本号为 1 时才 PUT 更新。
当第一个请求先达到 ES,发现版本号为 5 与自己预料的是正确的的,则将 name 修改为了 1,此时版本号_seq_no 会自动加一个随机数,改为了 8;
第二个请求后随后到达,准备将 name 修改 2,但是发现此时的版本号为 8 与自己预料的版本号 5 对不上,则该 PUT 操作就不会执行,会显示 409 错误码。
- PUT customer/external/1?if_seq_no=5&if_primary_term=1 {“name”:”1”}
- PUT customer/external/1?if_seq_no=5&if_primary_term=1 {“name”:”2”}
4、更新数据
- POST customer/external/1/_update
请求体为:
{
“doc”:{
“name”: “John”
}
}
- POST customer/external/1
请求体为:
{
“name”: “John”
}
PUT customer/external/1
请求体为
{
“name”: “John”
}
不同点:
1.POST 发送请求携带上 update,请求体需要“doc”字段,doc 下才是文档数据
2.POST 发送请求携带上 update,会对比要更新的数据,如果不存在则会将请求体数据创建
如果存在
- 对比数据相同:则什么也不做,version、seq_no 都不会发生变化
- 对比数据不相同:发生更新操作,此时版本号才会发生变化(只有对比更新的数据有不同,才会进行更新)
3.POST 不携带 update 和 PUT 请求,原来数据存在的话,都会发生更新,不会去进行对比,不存在就会创建
共同点: 1.都可以在原来的基础上,更新增加属性
5、删除文档&索引
ES 中没有直接删除类型 Type
- DELETE /customer/external/1 删除文档
- DELETE /customer 删除索引
6、bulk 批量 API
在 kibana 中批量操作形式为:
- 其中 action 可选为 index/create/update/delete
- 其中 metadata 可选为_index,_type,_id
- 其中 requestbody 为数据
create 和 index 的区别:
如果数据存在,使用 create 操作失败,会提示文档已经存在,使用 index 则可以执行成功,如果存在会进行覆盖
bulk 批量操作,一个操作失败不会影响后续的操作
{"action": {metedta}}
{requestbody}
{"action": {metedta}}
{requestbody}
举例:
- POST customer/external/_bulk
{"index": {"_id": 1}}
{"name": "1"}
{"index": {"_id": 2}}
{"name": "2"}
- POST _bulk
{"delete": {"_index":"website", "_type":"blog","_id":"123"}} // 删除数据,初次会提示404,但不影响后续的操作
{"create": {"_index":"website", "_type":"blog","_id":123}} // 创建数据
{"title":"My first blog post"}
{"index": {"_index":"website","_type":"blog"}} // 插入数据
{"title": "My second blog post"}
{"update":{"_index":"website", "_type":"blog","_id":"123"}} // 更新数据
{"doc":{"title":"My updated blog post"}}
四、复杂检索
首先批量导入数据 POST /bank/account/_bulk
https://raw.githubusercontent.com/elastic/elasticsearch/master/docs/src/test/resources/accounts.json
支持两种方式:
- 将请求检索参数防止在 GET 请求路径背后 例如:
- GET /bank/_search?q=*&sort=account_number:sort
- 将请求检索参数放置在请求体中
- GET bank/_search
{
"query": {
"match_all":{}
},
"sort":[
{
"account_number": "asc"
}
]
}
1)基本语法格式
ES 提供了一个可以执行查询的 json 风格的 DSL(domain-specific language 领域特定语言),也被称为 Query DSL。
1、全记录分页排序查询
# 分页查询 from和size相当于MySQL中的limit
GET bank/_search
{
"query": {
"match_all":{}
},
"sort": [
{
"balance": {
"order": "desc"
}
}
],
"from": 0,
"size": 5
}
2、特定字段分页排序查询
# 查询特定字段的分页查询,_source指定查询字段
GET bank/_search
{
"query": {
"match_all":{}
},
"sort": [
{
"balance": {
"order": "desc"
}
}
],
"from": 0,
"size": 5,
"_source": ["balance","firstname"]
}
3、match 查询、term 查询
term 查询,和 match 一样匹配某个属性的值,区别在于:
- term 查询只能用于查询非文本字段,查询文本字段会始终显示结果数为 0;或者 term 与 keyword 搭配,查询全量字符串
- 文本字段全文检索字段用 match
官方推荐:term 用于查询非文本字段,match 用于查询文本字段
# match用在字段为数字上相当于精确查询
GET bank/_search
{
"query": {
"match": {
"account_number": 20
}
}
}
# match模糊检索,会对检索条件进行分词匹配,不指定排序的话,结果会按照评分进行排序
GET bank/_search
{
"query": {
"match": {
"address": "mill lane"
}
}
}
# match全文检索,指定了排序则会按照排序字段进行排序
GET bank/_search
{
"query": {
"match": {
"address": "mill lane"
}
},
"sort": [
{
"balance": {
"order": "desc"
}
}
]
}
# term查询,和match一样匹配某个属性的值
# 只能用于查询非文本字段,查询文本字段会始终显示结果数为0
# 全文检索字段用match,其他非text字段用term
# 官方推荐:term用于查询非文本字段,match用于查询文本字段
GET bank/_search
{
"query": {
"term": {
"balance": 32838
}
}
}
# 或者term与keyword搭配,查询全量字符串
GET bank/_search
{
"query": {
"term": {
"lastname.keyword": "Bates"
}
}
}
4、match_phrase 短语匹配查询、keyword 全量精确查询
match_phrase 和 keyword 区别
- match_phrase 是将查询词不可拆分进行查询,只有完整包含了这个短语就可以得到匹配
- keyword 则是精确查询,要求查询字段只能是该短语,而不是仅仅的包含关系
# match_pharse 短语匹配,将查询条件当成不可分割的短语进行匹配查询
# 包含了完成的短语mill lane会检索出来
GET bank/_search
{
"query": {
"match_phrase": {
"address": "789 Madison"
}
}
}
# 对于有一条记录为"address" : "789 Madison Street"
# match_phrase可以查到一条记录,而keyword差不到该条记录,是精确查询
# keyword全量精确匹配
GET bank/_search
{
"query": {
"match": {
"address.keyword" : "789 Madison"
}
}
}
5、multi_match 多字段匹配查询
# multi_match 多字段查询,query的词也会进行分词,两个字段有任意一个字段包含分的词检索出来,是or关系
GET /bank/_search
{
"query": {
"multi_match": {
"query": "mill lane",
"fields": ["state", "address"]
}
}
}
6、bool 多重条件复合查询
bool 多重查询可以用上的条件交并集:must、must_not、should、filter
must 和 filter 配合 range 都可以进行过滤,区别在于:must 会贡献评分,但是 filter 不会贡献评分
- must:数组内的条件必须都满足
# bool中可以有多个查询条件,这里的must含义就是must数组中的条件都必须满足
GET bank/_search
{
"query": {
"bool": {
"must": [
{"match":
{
"gender": "F"
}
},
{
"match": {
"address": "mill"
}
}
]
}
}
}
- must_not:数组内的条件必须都不满足
# 复合查询,must:必须满足,must_not:必须不满足
# 查找出gender为M,address中有mill且age不是38的记录
GET bank/_search
{
"query": {
"bool": {
"must": [
{"match":
{
"gender": "M"
}
},
{
"match": {
"address": "mill"
}
}
],
"must_not": [
{
"match":
{
"age": 38
}
}
]
}
}
}
- should:数组内的条件最好满足,满足会有匹配度加分
# 复合查询,其中的should表示满足最好,不满足也可以,是加分项,满足了评分会更高
GET bank/_search
{
"query": {
"bool": {
"must": [
{"match":
{
"gender": "M"
}
},
{
"match": {
"address": "mill"
}
}
],
"must_not": [
{
"match":
{
"age": 18
}
}
],
"should": [
{
"match":
{
"lastname": "Wallace"
}
}
]
}
}
}
- filter:过滤
# must和filter配合range都可以进行过滤
# 区别在于:must会贡献评分,但是filter不会贡献评分
GET bank/_search
{
"query": {
"bool": {
"must": [
{
"range": {
"age": {
"gte": 18,
"lte": 30
}
}
}
]
}
}
}
GET bank/_search
{
"query": {
"bool": {
"filter": {
"range": {
"age": {
"gte": 18,
"lte": 30
}
}
}
}
}
}
7、aggragations 聚合查询
聚合提供了从数据中分组和提取数据的能力,最简单的聚合方法大致等于 SQL 中的 group by 和 SQL 聚合函数。ES 中,您有执行搜索返回 hits(命中结果),并且同时返回聚合结果,将一个响应中的所有 hits(命中结果)隔开的能力,可以执行查询和多个聚合,并且在一次使用中得到各自的返回结果,使用一次简洁和简化的 API 来避免网络往返
聚合语法:
"aggregations" : {
"<aggregation_name>" : { # 这次聚合的名字,自定义方便展示在结果集中
"<aggregation_type>" : { # 聚合类型
<aggregation_body> # 聚合体
}
[,"meta" : { [<meta_data_body>] } ]?
[,"aggregations" : { [<sub_aggregation>]+ } ]? # 聚合内嵌套子聚合,是在第一个查询的结果集上再次进行子聚合查询
}
[,"<aggregation_name_2>" : { ... } ]* # 第二个聚合,和第一聚合是相互独立的
}
1.搜索address中包含mill的所有人的年龄分布以及平均年龄
GET bank/_search
{
"query": {
"match": {
"address": "mill"
}
},
"aggs": {
"aggAge": {
"terms": { # terms相当于SQL中的count + group by,这里是先年龄分组计算每个分组总数
"field": "age",
"size": 10
}
},
"ageAvg":{
"avg": { # 第二个聚合:计算平均年龄
"field": "age"
}
}
}
}
2.按照年龄聚合,并且请求这些年龄段这些人的平均薪资
# 子查询,类似于MySQL中group by 然后avg
GET bank/_search
{
"query": {
"match_all": {}
},
"aggs": {
"aggAge": {
"terms": {
"field": "age",
"size": 10
},
"aggs": { # 子查询,在上一次聚合的结果中再次查询
"aggAvg": {
"avg": {
"field": "balance"
}
}
}
}
}
}
3.查出所有年龄分布,并且这些年龄中的性别为M的平均薪资和F的平均薪资以及这个年龄段的总体平均薪资
GET bank/_search
{
"query": {
"match_all": {}
},
"aggs": {
"aggAge": {
"terms": {
"field": "age", # 首先按照年龄进行聚合,terms计算count
"size": 100
},
"aggs": {
"avgGender": {
"terms": {
"field": "gender.keyword" # 在年龄聚合的桶内再用性别进行聚合
},
"aggs": {
"aggBalance": {
"avg": {
"field": "balance" # 在性别聚合的桶内在计算桶内的平均薪资
}
}
}
},
"avgBalanceOnAge":{
"avg": {
"field": "balance" # 在年龄聚合的桶内计算平均薪资
}
}
}
}
}
}
2)Mapping 映射
Mapping 是一个定义文档和所包含的字段如何保存和索引的,举例,使用 mapping 可以用来定义:
- 哪个字符串字段应该被当成全文检索字段(full text fields)
- 哪个字段包含数字、日期、或者地理标志
- 日期的格式
- 自定义映射规则来执行动态添加属性
1.查询映射关系
PUT /my_index
{
"mappings": {
"properties": {
"age": {"type": "Long"},
"email": {"type": "keyword"},
"name": {"type": "text"}
}
}
}
2.建立索引的mapping映射
# ES7.x不再支持Types(类似MySQL中的表),所以这里没有在my_index在指定Types
# keyword会进行精确匹配,而不再分词全文匹配
PUT /my_index/_mapping
{
"properties": {
"employee_id": {
"type": "keyword",
"index": false
}
}
}
3.修改指定索引的映射
3.1 增加新的字段
PUT /my_index/_mapping
{
"properties": {
"employee_id": {
"type": "keyword",
"index": false # index表示employee_id不再可以被查询。(Fields that are not indexed are not queryable.)
}
}
}
3.2 修改已有的字段映射
建立了映射后只能新增字段,而不能修改以前的字段属性,因为修改已存在的字段会让已经存在的数据失效。
如果你确实需要修改某个字段的映射,你需要重新建立一个映射关系的索引,然后将你的数据reindex到你新建的索引中
3.3 数据迁移到新的索引
3.3.1 首先建立新的索引mapping关系
PUT /newbank
{
"mappings": {
"properties": {
"account_number": {
"type": "long"
},
"address": {
"type": "text"
},
"age": {
"type": "integer"
},
"balance": {
"type": "long"
},
"city": {
"type": "keyword"
},
"email": {
"type": "keyword"
},
"employer": {
"type": "keyword"
},
"firstname": {
"type": "text"
},
"gender": {
"type": "keyword"
},
"lastname": {
"type": "text"
},
"state": {
"type": "keyword"
}
}
}
}
3.3.2 数据迁移reindex
【固定写法】对于没有建立类型的索引之间相互迁移数据
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "tweet "
}
}
将旧索引的types下的数据进行迁移
因为我们旧索引建立了accout类型,索引迁移需要将索引和类型指定迁移到哪个索引下
POST _reindex
{
"source": {
"index": "bank",
"type": "account"
},
"dest": {
"index": "newbank"
}
}
# 可以看到数据迁移了过来,并且没有了type
# 以后都不用type,老的数据都可以通过reindex迁移过来
GET newbank/_search
五、分词
一个 tokenizer(分词器)接受一个字符流,将之分隔为独立的 tokens(词元,通常是独立的单词),然后输出 tokens 流。
例如:whitespace tokenizer 遇到空白字符时分隔文本,它会将文本”Quick brown fox!”分隔为【Quick,brown,fox!】
该 tokenizer(分词器)还负责记录各个 term(词条)的顺序或 position 位置(用于 phrase 短语和 word proximity 词近邻查询),以及 term(词条)所代表的原始 word(单词)的 start(起始)和 end(结束)的 character offsets(字符偏移量)用于高亮显示搜索的内容,ElasticSearch 提供了很多内置的分词器,可以用来构建 custom analyzers(自定义分词器)
# 使用标准特定的分词器来进行分词
POST _analyze
{
"analyzer": "standard",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}
1、安装 ik 分词器
# 进入容器挂载到外部的目录或未挂载进入容器内的目录
cd /mydata/elasticsearch/plugins
mkdir ik
cd ik
# 下载对应ES版本的ik分词器,这里选择7.4.2版本
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip
unzip elasticsearch-analysis-ik-6.8.4.zip
cd ../..
chmod -R 777 plugins/
docker exec -it elasticsearch /bin/bash
cd /usr/share/elasticsearch/plugins/
# 查看安装好的插件
elasticsearch-plugin
# 重启让插件生效
docker restart elasticsearch
2、测试 ik 分词器
ik 分词器提供两种:ik_smart 和 ik_max_word
ik_smart:智能分词,将输入词进行拆分
ik_max_word:保留所有可能搭配的词组组合
POST _analyze
{
"analyzer": "ik_smart",
"text": "我是中国人"
}
3、自定义词库
ik 分词器有很多网络热词无法进行分词,所以这里我们可以自定义词库
我们可以指定一个远程的词库,让 ik 分词器可以去远程拉取最新的单词作为新的词元进行分解,这里建立远程的词库有两种方式:
- 写一个项目来处理 ik 发送的请求,来返回新的单词
- 安装 Nginx,让 ik 分词器给 Nginx 发送请求,Ngix 将这个静态资源返回
更改 ES 栈大小,之前是-Xmx128m,有点小,这里改为 512m,方法为将之前的 ES 容器删掉,因为之前是将容器内的数据挂载到了 centos 下的目录,所以数据不会丢失,新建一个 ES 容器再次挂载到这些目录即可
docker rm -f elasticsearch
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
4、安装 Ngnix
# 首先随便创建一个nginx实例,主要是将其中的配置复制出来
cd /mydata
mkdir nginx
docker pull nginx:1.10
docker run -p 80:80 --name nginx -d nginx:1.10
# 将nginx中的配置复制出来
docker container cp nginx:/etc/nginx .
cd nginx
ls # 就可以查看复制出来的文件
cd ..
mv nginx conf # 将nginx配置移动到conf文件夹下
mkdir nginx # 新建nginx文件夹
mv conf nginx/ # 将整个conf文件夹移动到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
浏览器访问虚拟机 ip 地址http://192.168.2.200/即成功
cd /ngnix/html
echo '<h1>hello nginx</h1>' >> index.html
5、在 Nginx 下自定义静态资源词库
# 在html下创建es文件夹,这里放入自定义分词器的词库内容
mkdir es
cd es
vi fenci.txt
# 输入你的词元,例如以下
# 修改ik分词器请求分词词库地址
cd elasticsearch/plugins/ik
cd config
vi IKAnalyzer.cfg.xml
填充上 nginx 代理的静态资源地址(如果设置了 centos 的 ip 地址为宿主机 ip 地址同一个网段,则可以填写 centos 的地址,这里填写 192.168.2.200)
# 让分词器生效
docker restart elasticsearch
docker update nginx --restart=always
地址栏访问 kibana,可以看到尚硅谷成为了一个词元,没有再被拆开为【尚,硅,谷】,说明自定义词库已经生效
(kibana 显示 not ready yet 的,注意因为我们新建了 ES 容器,对应容器的 ip 地址也发生了变化,所以新建 kibana 容器,指定好新的 ES 地址就可以访问了,上面步骤也都是有的)
五、java 操作 ES
java 操作 ES 有多重选择
1)9300:TCP
- spring-data-elasticsearch:transport-api.jar
- springboot 版本不同,transport-api.jar 不同,不能适配 es 高版本
- 7.x 已经不建议使用,8 以后就要废弃
- spring-boot-starter-data-elasticsearch
请注意 springboot 版本以及 elasticsearch 版本,是对官方 restClient 更简化的封装,推荐
2)9200:HTTP
- JestClient:非官方,更新慢
- RestTemplate:模拟发送 HTTP 请求,ES 很多 DSL 都要自己封装,麻烦
- HttpClient:同上
- Ok-Http:同上
- Elasticsearch-Rest-Client:官方 RestClient,封装了 ES 操作,上手比较繁琐
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。