【Elasticsearch教程】-Elasticsearch基本操作
Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。
文章目录
前言
之前的文章讲解了如何进行安装Elasticsearch【Elasticsearch教程】-安装,现在我们来看看Elasticsearch的基本操作,如新增,删除,聚合,查询等操作。
一、相关概念
近实时
Elasticsearch是一个近实时的数据搜索和分析平台。这意味着从索引文档到可搜索文档都会有一段微小
的延迟。
集群cluster
集群(cluster)是一个或多个节点(node)的集合,这些节点将共同拥有完整的数据,并跨节点提供联合索引、搜索和分析功能。
注意
:请确保不要在不同的环境中使用相同的集群名称,否则可能会导致节点加入错误的集群。
只有一个节点的集群是有效的,而且有特殊的用处,尤其是可以在单节点集群进行快速的开发、测试。此外,可以存在多个独立的集群,每个集群都有自己唯一的集群名称
节点Node
节点是一个Elasticsearch的运行实例.多个节点组成集群,节点存储数据,并参与集群的索引、搜索和分析功能.可以通过集群名称将节点配置为加入特定集群。默认情况下,每个节点都被设置为加入一个名为Elasticsearch的集群。这意味着,如果在网络上启动了多个节点,并且假设它们可以彼此发现,那么它
们都将自动形成并加入一个名为Elasticsearch的集群。
在单个集群中,可以有任意多个节点
索引Index
索引(index)是具有某种相似特性的文档集合。相当于mysql中的一个库
文档Document
文档是可以被索引的基本信息单元。相当于数据库中的record记录。
分片shard和副本replica
索引可能会存储大量数据,这些数据可能会超出单个节点的硬件限制。如果我们将大量的文档存储在单个节点上,有可能会导致访问速度减慢同时有可能超过了单个节点的磁盘最大容量。因此可以通过分片解决这个问题。Elasticsearch提供了将索引水平切分为多段的能力。创建索引时,只需定义所需的分片
数量。每个分片本身就是一个具有完全功能的独立“索引”,可以分布在集群中的任何节点上。
- 分片可以水平拆分数据,实现大数据存储和分析。
- 可以跨分片(可能在多个节点上)进行分发和并行操作,从而提高性能和吞吐量。
在随时可能发生故障的网络或云环境中,如果某个分片或节点以某种方式脱机或因何种原因丢失,则强烈建议用户使用故障转移机制。为此,Elasticsearch提出了将索引分片复制一个或多个拷贝,称为副本。 - 副本在分片或节点发生故障时提供高可用性。因此,需要注意的是,副本永远不会分配到复制它的原始主分片所在的节点上。也就是分片和对应的副本不可在同一节点上。这很容易理解,如果副本和分片在同一节点上,当机器发生故障时会同时丢失,起不到容错的作用。
- 通过副本机制,可以提高搜索性能和水平扩展吞吐量,因为可以在所有副本上并行执行搜索
二、Elasticsearch操作
我们都知道Elasticsearch为我们提供了强大的Rest API,我们通过Rest API可以进行Elasticsearch的相关操作,如查询集群的状态,文档新增,删除等操作。
- 检查集群、节点和索引的运行状况、状态和统计信息。
- 管理集群、节点和索引数据和元数据。
- 对索引执行CRUD(创建、读取、更新和删除)和搜索操作
- 执行高级搜索操作,如分页、排序、过滤、脚本、聚合和其他操作
1.检查集群
集群健康信息
curl --location --request GET 'http://localhost:9200/_cat/health?v'
- status:集群的健康状态,有三种值:1、green(一切正常) 2、red(由于某些原因,某些数据不可用) 3、yellow(所有数据都可用,但某些副本尚未分配)
- node.total:节点总数
- node.data:节点数据
获取节点
curl --location --request GET 'http://localhost:9200/_cat/nodes?v'
获取所有索引
curl --location --request GET 'http://localhost:9200/_cat/indices?v'
说明还没有索引,我们等会再进行创建
2.对索引执行CRUD
创建索引
curl --location --request PUT 'http://localhost:9200/indexcus?pretty'
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "indexcus"
}
- ?pretty:通过json格式返回相关的结果
再次查询索引,将会查询出相关的索引
- pri:分片数
- rep:副本数(默认1)
- doc.count:文档数
- doc.deleted:删除的文档数
- store.size:存储大小
- pri.store.size:分片大小
查询文档和索引
- 创建文档
curl --location --request PUT 'http://localhost:9200/indexcus/_doc/1?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
"name":"username",
"password":"123456"
}'
{
"_index": "indexcus",
"_type": "_doc",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
注意:
一 定 要 把 /config/elasticsearch.yml 文 件 中 的network.host属性值改为本机IP,这样其他机器就可以访问elasticsearch的服务
如果我们创建文档之前,没有创建相应的索引,索引会自动创建。这点和mongodb操作的时候一致
2. 获取文档
curl --location --request GET 'http://localhost:9200/indexcus/_doc/1?pretty'
{
"_index": "indexcus",
"_type": "_doc",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"name": "username",
"password": "123456"
}
}
- _source:返回文档的内容
- _type:数据类型
- _id:id
- _version:版本
- found:是否查找到
再进行查询索引的时候,可以发现索引下面的文档数为1了
- 删除文档
curl --location --request DELETE 'http://localhost:9200/indexcus/_doc/1?pretty'
{
"_index": "indexcus",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
再进行查询索引的时候,文档数将变为1
注意:
在Elasticsearch中,删除操作只是把需要删除的文档的ID记录到了一个列表中,当段合并时才有可能真正把源文档删除。
- 删除索引
curl --location --request DELETE 'http://localhost:9200/indexcus?pretty'
{
"acknowledged": true
}
再查询索引将没有了
- 修改数据
更新操作调用的方法和新增的一样,将body中的值改一下就可以。
curl --location --request PUT 'http://localhost:9200/indexcus/_doc/1?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
"name":"username",
"password":"123456",
"age":18,
"address":"sh"
}'
{
"_index": "indexcus",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
Elasticsearch实际上并不是进行就地更新,每当进行更新时,Elasticsearch会删除旧文档,然后索引一个新文档,但这对用户来说是一次调用。
- 批量操作
批量API不会由于其中一个操作失败而失败。如果一个操作由于某个原因失败,它将继续处理后面的其余操作。当批量API返回时,它将为每个操作提供一个状态,以便用户检查特定操作是否失败。
curl --location --request POST 'http://localhost:9200/indexcus/_bulk?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{"index":{"_id":"1","_type":"_doc"}}
{"name":"username"}
{"index":{"_id":"2","_type":"_doc"}}
{"name":"username"}
'
{
"took": 94,
"errors": false,
"items": [
{
"index": {
"_index": "indexcus",
"_type": "_doc",
"_id": "1",
"_version": 3,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 2,
"status": 200
}
},
{
"index": {
"_index": "indexcus",
"_type": "_doc",
"_id": "2",
"_version": 4,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 2,
"status": 200
}
}
]
}
由于我的es的版本为6.x的版本,在进行批量操作的时候,指定"_type":"_doc"先关的类型,不然会报如下错误:
{
"error": {
"root_cause": [
{
"type": "action_request_validation_exception",
"reason": "Validation Failed: 1: type is missing;2: type is missing;"
}
],
"type": "action_request_validation_exception",
"reason": "Validation Failed: 1: type is missing;2: type is missing;"
},
"status": 400
}
2.搜索以及高级搜索
执行搜索有两种基本方法:
- 通过REST请求URI发送搜索参数
- 通过REST请求主体(body形式)发送搜索参数。请求主体方法表现形式更强大,用更可读的JSON格式定义搜索
2.1 使用操作
- 构建数据
由于进行搜索的时候,我们需要大量的数据记性操作,可以再官网上面下载相关的account.json,但是我访问的时候,已经不存在了。
所以我们我这边是使用json-generator进行生成的,就用默认的即可,
生成之后,将json下载下来导入即可。 - 导入数据
这个由于我是在window上操作的,我是下载了json-to-es-bulk的插件,将json-generator转换为es中能识别的bulk的数据。
具体步骤:
- 下载:json-to-es-bulk
- 执行命令
# 安装
npm install
# node index.js -f generator生成的文件路劲 --index 索引名 --type 个人定义
node index.js -f C:\Users\Tony\Desktop\generated.json --index=account --type _doc
- 执行上面的命令之后会生成request-data.txt
- 进入request-data.txt所在文件夹,将后缀改为json即可
curl --location --request POST 'http://localhost:9200/bank/account/_bulk?pretty' \
--header 'Content-Type: application/json' \
--data-binary '@/D:/json-to-es-bulk/json-to-es-bulk-master/request-data.json'
执行之后,会报如下错误:
type": "mapper_parsing_exception", "reason": "Field [_id] is a metadata field and cannot be added inside a document. Use the index API request parameters."
我们将request-data.json中的_id
变为id
就可以了
我们来看看索引:
索引已经创建成功了,之后文档有424个文档。我们通过以上的文档进行查询的相关操作。
- 查询所有文档
curl --location --request GET 'http://localhost:9200/account/_search?q=*&pretty'
q=*
:查询所有文档
took:
查询所用时间
timed_out
:是否超时
_shards
:搜索了多少分片,以及搜索成功和失败的分片的计数
hits
:实际的搜索结果集
上面的参数是在url中定义查询参数,我们也可以将参数放在body中
curl --location --request GET 'http://localhost:9200/indexcus/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
"query":{"match_all":{}}
}'
查询适合url中一样的结果,放在body中有一个好处是可读性更强,可以写更多的条件等。
- Elasticsearch查询语言
Elasticsearch提供了一种JSON风格的语言,可以使用它来执行查询。这被称为Query DSL。
{"match_all":{}}
match_all查询表示搜索指定索引中的所有文档
- 分页查询
可以通过from和size进行分页查询,size和from不需要成对出现,可以单独使用。
curl --location --request GET 'http://localhost:9200/account/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
"query":{"match_all":{}},
"size":1
}'
这样只会查询1调数据,size默认值为10.
curl --location --request GET 'http://localhost:9200/account/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
"query":{"match_all":{}},
"size":10,
"from":10
}'
这样就相当于mysql中的limit参数
6.排序操作
我们可以使用sort对相应的文档进行排序操作
curl --location --request GET 'http://localhost:9200/account/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
"query":{"match_all":{}},
"sort":{
"age":{"order":"desc"}
}
}'
上面是通过sort对年龄age字段进行排序。
- 返回指定属性并通过自定字段排序
curl --location --request GET 'http://localhost:9200/account/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
"query":{"match_all":{}},
"sort":{"age":{"order":"desc"}},
"_source":["age","balance"]
}'
只返回我们需要使用的字段,同时对age进行了排序。
- 匹配查询
curl --location --request GET 'http://localhost:9200/account/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
"query":{"match":{"age":20}}
}'
查询age为20的数据
- bool查询
布尔查询是指使用布尔逻辑的方式把基本的查询组合成复杂的查询
curl --location --request GET 'http://localhost:9200/account/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
"query":{
"bool":{
"must":[
{"match":{"address":"Walland"}},
{"match":{"address":"Maine"}}
]
}
}
}'
- must:指定文档被视为匹配项时必须为真的所有查询,同时包含Walland和Maine才能成功。
- should:指定一个查询列表,其中任何一个查询为真,文档即被视为匹配,也就是只需满足其中一个条件即可
- must_not:指定一个查询列表,其中任何一个查询都不能为真,文档才能被视为匹配
可以在bool查询中同时组合must、should和must_not子句。此外,还可以在这些bool子句中嵌套bool查询,以模拟任何复杂的多级布尔逻辑
- 条件过滤
curl --location --request GET 'http://localhost:9200/account/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
"query":{
"bool":{
"must":{"match_all":{}},
"filter":{
"range":{
"age":{
"gte":25,
"lte":40
}
}
}
}
}
}'
查询年龄大于等于25并且小于等于40的文档。
- 聚合查询
聚合提供了对数据分组和提取统计信息的能力。聚合功能可以理解为大致等同于SQL中的Group By和SQL聚合
函数的功能。在Elasticsearch中,可以执行返回命中文档的搜索,同时返回与搜索结果分离的聚合结果。从某种意义上说,这是非常强大和高效的,可以同时运行和查询多个聚合,并一次性获得两个(或多个)操作的结果,避免使用单一的API进行多次网络往返。
curl --location --request GET 'http://localhost:9200/account/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
"size":1,
"aggs":{
"group_by_gender":{
"terms":{
"field":"gender.keyword"
}
}
}
}'
上面是通过性别进行分组
总结
Elasticsearch给我们提供了对数据进行管理的Rest API,对文档,索引进行相应的管理。同时提供了很多数据处理的功能。出上面列出的功能,还有很多,大家可以亲自去实践一下(参考官网)。掌握更多Elasticsearch的相关技能,如相关规范,Elasticsearch的API,还有就是原理及其相关组件使用,后面会慢慢的出相应的文章。