03_ElasticSearch基本使用
cat API:
/_cat/allocation #查看单节点的shard分配整体情况 /_cat/shards #查看各shard的详细情况 /_cat/shards/{index} #查看指定分片的详细情况 /_cat/master #查看master节点信息 /_cat/nodes #查看所有节点信息 /_cat/indices #查看集群中所有index的详细信息 /_cat/indices/{index} #查看集群中指定index的详细信息 /_cat/segments #查看各index的segment详细信息,包括segment名, 所属shard, 内存(磁盘)占用大小, 是否刷盘 /_cat/segments/{index}#查看指定index的segment详细信息 /_cat/count #查看当前集群的doc数量 /_cat/count/{index} #查看指定索引的doc数量 /_cat/recovery #查看集群内每个shard的recovery过程.调整replica。 /_cat/recovery/{index}#查看指定索引shard的recovery过程 /_cat/health #查看集群当前状态:红、黄、绿 /_cat/pending_tasks #查看当前集群的pending task /_cat/aliases #查看集群中所有alias信息,路由配置等 /_cat/aliases/{alias} #查看指定索引的alias信息 /_cat/thread_pool #查看集群各节点内部不同类型的threadpool的统计信息, /_cat/plugins #查看集群各个节点上的plugin信息 /_cat/fielddata #查看当前集群各个节点的fielddata内存使用情况 /_cat/fielddata/{fields} #查看指定field的内存使用情况,里面传field属性对应的值 /_cat/nodeattrs #查看单节点的自定义属性 /_cat/repositories #输出集群中注册快照存储库 /_cat/templates #输出当前正在存在的模板信息
Elasticsearch安装分词插件
Elasticsearch提供插件机制对系统进行扩展,以安装analysis-icu这个分词插件为例
在线安装
#查看已安装插件 bin/elasticsearch‐plugin list #安装插件 bin/elasticsearch‐plugin install analysis‐icu #删除插件 bin/elasticsearch‐plugin remove analysis‐icu
注意:安装和删除完插件后,需要重启ES服务才能生效。
测试分词效果
# unicode支持,中文分词良好 POST _analyze { "analyzer":"icu_analyzer", "text":"中华人民共和国" }
离线安装
本地下载相应的插件,解压,然后手动上传到elasticsearch的plugins目录,然后重启ES实例就可以了。
上传本地文件到服务器:
# 创建目录 mkdir -p /opt/ik # 上传文件到服务器 scp D:/develop/elasticsearch-analysis-ik-7.17.7.zip root@192.168.211.156:/opt # 解压到该目录 unzip -d /opt/ik/ elasticsearch-analysis-ik-7.17.7.zip # 复制到ES插件目录下 docker cp /opt/ik ElasticSearch:/usr/share/elasticsearch/plugins/ik # 重启容器 docker stop ElasticSearch docker start ElasticSearch
注意:ik分词版本要与es版本保持一致,若不一致则需要修改分词器配置文件中的版本信息:
# 修改配置文件 vim plugin-descriptor.properties # 修改为你当前的es版本 elasticsearch.version=7.17.10
测试分词效果
# unicode支持,中文分词良好 POST _analyze { "analyzer":"icu_analyzer", "text":"中华人民共和国" } #ES的默认分词设置是standard,会单字拆分 POST _analyze { "analyzer":"standard", "text":"中华人民共和国" } #ik_smart:会做最粗粒度的拆 POST _analyze { "analyzer": "ik_smart", "text": "中华人民共和国" } #ik_max_word:会将文本做最细粒度的拆分 POST _analyze { "analyzer":"ik_max_word", "text":"中华人民共和国" }
分词结果:
扩展ik分词器分词词条:
# 配置扩展词条,分词器的配置文件 vim /usr/local/docker/volumes/ik/config/IKAnalyzer.cfg.xml # 新增自定义词条 vim my-custom.dic # 增加分词词条 芝士 芝士蛋糕 # 重启容器 docker stop ElasticSearch docker start ElasticSearch
配置自定义扩展词条前:
配置自定义扩展词条后:
创建索引时可以指定IK分词器作为默认分词器:
PUT /es_db { "settings": { "index": { "analysis.analyzer.default.type": "ik_max_word" } } }
ElasticSearch基本概念
关系型数据库 VS ElasticSearch
在7.0之前,一个 Index可以设置多个Types
目前Type已经被Deprecated,7.0开始,一个索引只能创建一个Type -“_doc”
传统关系型数据库和Elasticsearch的区别:
Elasticsearch- Schemaless /相关性/高性能全文检索
RDMS —事务性/ Join
索引(Index)
一个索引就是一个拥有几分相似特征的文档的集合。比如说,可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。
一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。
文档(Document)
Elasticsearch是面向文档的,文档是所有可搜索数据的最小单位。
日志文件中的日志项
一本电影的具体信息/一张唱片的详细信息
MP3播放器里的一首歌/一篇PDF文档中的具体内容
文档会被序列化成JSON格式,保存在Elasticsearch中
JSON对象由字段组成
每个字段都有对应的字段类型(字符串/数值/布尔/日期/二进制/范围类型)
每个文档都有一个Unique ID
可以自己指定ID或者通过Elasticsearch自动生成
一篇文档包含了一系列字段,类似数据库表中的一条记录
JSON文档,格式灵活,不需要预先定义格式
字段的类型可以指定或者通过Elasticsearch自动推算
支持数组/支持嵌套
文档元数据
元数据,用于标注文档的相关信息:
_index:文档所属的索引名
_type:文档所属的类型名
_id:文档唯—ld
_source: 文档的原始Json数据
_version: 文档的版本号,修改删除操作_version都会自增1
_seq_no: 和_version一样,一旦数据发生更改,数据也一直是累计的。Shard级别严格递增,保证后写入的Doc的_seq_no大于先写入的Doc的_seq_no。
_primary_term: _primary_term主要是用来恢复数据时处理当多个文档的
_seq_no一样时的冲突,避免Primary Shard上的写入被覆盖。每当Primary Shard发生重新分配时,比如重启,Primary选举等,_primary_term会递增1。
ElasticSearch索引操作
创建索引
索引命名必须小写,不能以下划线开头
格式: PUT /索引名称
#创建索引 PUT / es_db # 创建索引时可以设置分片数和副本数 PUT / es_db { "settings": { "number_of_shards": 3, "number_of_replicas": 2 } } #修改索引配置 PUT / es_db / _settings { "index": { "number_of_replicas": 1 } }
查询索引
格式: GET /索引名称
#查询索引 GET /es_db #es_db是否存在 HEAD /es_db
删除索引
格式: DELETE /索引名称
DELETE /es_db
ElasticSearch文档操作
示例数据
PUT /es_db { "settings": { "index": { "analysis.analyzer.default.type": "ik_max_word" } } } PUT /es_db/_doc/1 { "name": "张三", "sex": 1, "age": 25, "address": "广州天河公园", "remark": "java developer" } PUT /es_db/_doc/2 { "name": "李四", "sex": 1, "age": 28, "address": "广州荔湾大厦", "remark": "java assistant" } PUT /es_db/_doc/3 { "name": "王五", "sex": 0, "age": 26, "address": "广州白云山公园", "remark": "php developer" } PUT /es_db/_doc/4 { "name": "赵六", "sex": 0, "age": 22, "address": "长沙橘子洲", "remark": "python assistant" } PUT /es_db/_doc/5 { "name": "张龙", "sex": 0, "age": 19, "address": "长沙麓谷企业广场", "remark": "java architect assistant" } PUT /es_db/_doc/6 { "name": "赵虎", "sex": 1, "age": 32, "address": "长沙麓谷兴工国际产业园", "remark": "java architect" }
添加(索引)文档
格式: [PUT | POST] /索引名称/[_doc | _create ]/id
# 创建文档,指定id # 如果id不存在,创建新的文档,否则先删除现有文档,再创建新的文档,版本会增加 PUT /es_db/_doc/1 { "name": "张三", "sex": 1, "age": 25, "address": "广州天河公园", "remark": "java developer" } #创建文档,ES生成id POST /es_db/_doc { "name": "张三", "sex": 1, "age": 25, "address": "广州天河公园", "remark": "java developer" }
注意:POST和PUT都能起到创建/更新的作用,PUT需要对一个具体的资源进行操作也就是要确定id才能进行更新/创建,而POST是可以针对整个资源集合进行操作的,如果不写id就由ES生成一个唯一id进行创建新文档,如果填了id那就针对这个id的文档进行创建/更新。
Create -如果ID已经存在,会失败:
PUT /es_db/_create/1 { "name": "张三", "sex": 1, "age": 66, "address": "广州天河公园", "remark": "java developer" }
修改文档
全量更新,整个json都会替换,格式: [PUT | POST] /索引名称/_doc/id
如果文档存在,现有文档会被删除,新的文档会被索引
# 全量更新,替换整个json PUT /es_db/_doc/1/ { "name": "张三", "sex": 1, "age": 25 } #查询文档 GET /es_db/_doc/1
使用_update部分更新,格式: POST /索引名称/_update/id
update不会删除原来的文档,而是实现真正的数据更新
# 部分更新:在原有文档上更新 # Update ‐文档必须已经存在,更新只会对相应字段做增量修改 POST /es_db/_update/1 { "doc": { "age": 28 } } #查询文档 GET /es_db/_doc/1
使用 _update_by_query 更新文档
POST /es_db/_update_by_query { "query": { "match": { "_id": 1 } }, "script": { "source": "ctx._source.age = 30" } } GET /es_db/_doc/1
并发场景下修改文档
_seq_no和_primary_term是对_version的优化,7.X版本的ES默认使用这种方式控制版本,所以当在高并发环境下使用乐观锁机制修改文档时,要带上当前文档的_seq_no和_primary_term进行更新:
POST /es_db/_doc/2?if_seq_no=2&if_primary_term=2 { "name": "李四xxx" } GET /es_db/_doc/1
如果版本号不对,会抛出版本冲突异常,如下图:
查询文档
根据id查询文档,格式: GET /索引名称/_doc/id
GET /es_db/_doc/1
条件查询 _search,格式: /索引名称/_doc/_search
# 查询前10条文档
GET /es_db/_doc/_search
ES Search API提供了两种条件查询搜索方式:
REST风格的请求URI,直接将参数带过去
封装到request body中,这种方式可以定义更加易读的JSON格式
#通过URI搜索,使用“q”指定查询字符串,“query string syntax” KV键值对 #条件查询, 如要查询age等于28岁的 _search?q=*:*** GET /es_db/_doc/_search?q=age:28 #范围查询, 如要查询age在25至26岁之间的 _search?q=***[** TO **] 注意: TO 必须为大写 GET /es_db/_doc/_search?q=age[25 TO 26] #查询年龄小于等于28岁的 :<= GET /es_db/_doc/_search?q=age:<=28 #查询年龄大于28前的 :> GET /es_db/_doc/_search?q=age:>28 #分页查询 from=*&size=* GET /es_db/_doc/_search?q=age[25 TO 26]&from=0&size=1 #对查询结果只输出某些字段 _source=字段,字段 GET /es_db/_doc/_search?_source=name,age #对查询结果排序 sort=字段:desc/asc GET /es_db/_doc/_search?sort=age:desc
通过请求体的搜索方式会在后面详细讲解(DSL)
GET /es_db/_search { "query": { "match": { "address": "广州白云" } } }
删除文档
格式: DELETE /索引名称/_doc/id
DELETE /es_db/_doc/1
ElasticSearch文档批量操作
批量操作可以减少网络连接所产生的开销,提升性能:
支持在一次API调用中,对不同的索引进行操作
可以在URI中指定Index,也可以在请求的Payload中进行
操作中单条操作失败,并不会影响其他操作
返回结果包括了每一条操作执行的结果
批量写入
批量对文档进行写操作是通过_bulk的API来实现的
请求方式:POST
请求地址:_bulk
请求参数:通过_bulk操作文档,一般至少有两行参数(或偶数行参数)
第一行参数为指定操作的类型及操作的对象(index,type和id)
第二行参数才是操作的数据
参数类似于:
{"actionName":{"_index":"indexName", "_type":"typeName","_id":"id"}} {"field1":"value1", "field2":"value2"}
actionName:表示操作类型,主要有create,index,delete和update
批量创建文档create
POST _bulk {"create":{"_index":"article", "_type":"_doc", "_id":3}} {"id":3,"title":"yyj老师","content":"yyj老师666","tags":["java", "面向对象"],"create_time":1554015482530} {"create":{"_index":"article", "_type":"_doc", "_id":4}} {"id":4,"title":"yyj2老师","content":"yyj2老师NB","tags":["java", "面向对象"],"create_time":1554015482530}
普通创建或全量替换index
POST _bulk {"index":{"_index":"article", "_type":"_doc", "_id":3}} {"id":3,"title":"yyj老师","content":"yyj老师666","tags":["java", "面向对象"],"create_time":1554015482530} {"index":{"_index":"article", "_type":"_doc", "_id":4}} {"id":4,"title":"yyj2老师","content":"yyj2老师NB","tags":["java", "面向对象"],"create_time":1554015482530}
如果原文档不存在,则是创建
如果原文档存在,则是替换(全量修改原文档)
批量删除delete
POST _bulk {"delete":{"_index":"article", "_type":"_doc", "_id":3}} {"delete":{"_index":"article", "_type":"_doc", "_id":4}}
批量修改update
POST _bulk {"update":{"_index":"article", "_type":"_doc", "_id":3}} {"doc":{"title":"ES大法必修内功"}} {"update":{"_index":"article", "_type":"_doc", "_id":4}} {"doc":{"create_time":1554018421008}}
组合应用
POST _bulk {"create":{"_index":"article", "_type":"_doc", "_id":3}} {"id":3,"title":"yyj老师","content":"yyj老师666","tags":["java", "面向对象"],"create_time":1554015482530} {"delete":{"_index":"article", "_type":"_doc", "_id":3}} {"update":{"_index":"article", "_type":"_doc", "_id":4}} {"doc":{"create_time":1554018421008}}
批量读取
es的批量查询可以使用mget和msearch两种。其中mget是需要我们知道它的id,可以指定不同的index,也可以指定返回值source。msearch可以通过字段查询来进行一个批量的查找。
_mget
#可以通过ID批量获取不同index和type的数据 GET _mget { "docs": [{ "_index": "es_db", "_id": 1 }, { "_index": "article", "_id": 4 } ] } #可以通过ID批量获取es_db的数据 GET /es_db/_mget { "docs": [{ "_id": 1 }, { "_id": 4 } ] } #简化后 GET /es_db/_mget { "ids": ["1", "2"] }
_msearch
在_msearch中,请求格式和bulk类似。查询一条数据需要两个对象,第一个设置index和type,第二个设置查询语句。查询语句和search相同。如果只是查询一个index,我们可以在url中带上index,这样,如果查该index可以直接用空对象表示。
GET /es_db/_msearch {} {"query" : {"match_all" : {}}, "from" : 0, "size" : 2} {"index" : "article"} {"query" : {"match_all" : {}}}