Elasticsearch 是一个基于Apache Lucene的开源分布式搜索和分析引擎,广泛应用于全文搜索、结构化搜索、分析等多种场景。
Easysearch 作为Elasticsearch 的国产化替代方案,不仅保持了与原生Elasticsearch 的高度兼容性,还在功能、性能、稳定性和扩展性方面进行了全面提升。以下是Easysearch的基本知识和语法:
基本概念
- 节点(Node):Elasticsearch集群中的单个服务器。
- 集群(Cluster):由一个或多个节点组成,拥有唯一的集群名。
- 索引(Index):类似于关系数据库中的数据库,一个索引包含了一系列的文档。
- 类型(Type):索引中的一个逻辑分类,在Elasticsearch 6.x以后已被弃用。
- 文档(Document):索引中的基本数据单位,类似于关系数据库中的行。
- 字段(Field):文档中的一个属性,类似于关系数据库中的列。
- 分片(Shard):索引可以被分成多个分片来分布存储。
- 副本(Replica):分片的副本,用于高可用性和故障恢复。
查看集群信息
在Elasticsearch中,可以通过多个API来查看集群的各种信息,包括集群的健康状况、节点信息和索引状态。以下是一些常用的查看集群信息的API和示例:
查看集群健康状况
_cluster/health
API可以查看集群的健康状态,包括集群是否处于正常状态、节点数量、分片状态等。
GET /_cluster/health
示例响应:
{
"cluster_name": "my_cluster",
"status": "green",
"timed_out": false,
"number_of_nodes": 3,
"number_of_data_nodes": 3,
"active_primary_shards": 5,
"active_shards": 10,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"number_of_in_flight_fetch": 0,
"task_max_waiting_in_queue_millis": 0,
"active_shards_percent_as_number": 100.0
}
查看集群状态
_cluster/stats
API可以查看集群的详细状态,包括索引、节点、分片等信息。
GET /_cluster/stats
示例响应:
{
"cluster_name": "my_cluster",
"status": "green",
"indices": {
"count": 10,
"shards": {
"total": 20,
"primaries": 10,
"replication": 1.0,
"index": {
"shards": {
"min": 1,
"max": 5,
"avg": 2.0
}
}
}
},
"nodes": {
"count": {
"total": 3,
"data": 3,
"coordinating_only": 0,
"master": 1,
"ingest": 2
},
"os": {
"available_processors": 12,
"allocated_processors": 12
},
"process": {
"cpu": {
"percent": 10
},
"open_file_descriptors": {
"min": 100,
"max": 300,
"avg": 200
}
}
}
}
查看节点信息
_nodes
API可以查看集群中节点的详细信息,包括节点角色、IP地址、内存使用情况等。
GET /_nodes
示例响应:
{
"cluster_name": "my_cluster",
"nodes": {
"node_id_1": {
"name": "node_1",
"transport_address": "192.168.1.1:9300",
"host": "192.168.1.1",
"ip": "192.168.1.1",
"roles": ["master", "data", "ingest"],
"os": {
"available_processors": 4,
"allocated_processors": 4
},
"process": {
"cpu": {
"percent": 10
},
"open_file_descriptors": 200
}
},
"node_id_2": {
"name": "node_2",
"transport_address": "192.168.1.2:9300",
"host": "192.168.1.2",
"ip": "192.168.1.2",
"roles": ["data"],
"os": {
"available_processors": 4,
"allocated_processors": 4
},
"process": {
"cpu": {
"percent": 15
},
"open_file_descriptors": 150
}
}
}
}
查看索引状态
_cat/indices
API可以查看集群中所有索引的状态,包括文档数、存储大小、分片数等信息。
GET /_cat/indices?v
示例响应:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open index_1 SxNUd84vRl6QH5P7g0T4Vg 1 1 0 0 230b 230b
green open index_2 NxEYib4yToCnA1PpQ8P4Xw 5 1 100 1 10mb 5mb
这些API可以帮助你全面了解Elasticsearch集群的状态和健康状况,从而更好地管理和维护集群。
增删改查
创建索引
PUT /my_index
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
}
}
删除索引
DELETE /my_index
添加文档
POST /my_index/_doc/1
{
"name": "John Doe",
"age": 30,
"occupation": "Engineer"
}
PUT /my_index/_doc/1
{
"name": "John Doe",
"age": 30,
"occupation": "Engineer"
}
新建文档
PUT /my_index/_create/1
{"a":1}
新建之后再执行报错:
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[23]: version conflict, document already exists (current version [1])",
"index_uuid": "1xWdHLTaTm6l6HbqACaIEA",
"shard": "0",
"index": "ss"
}
],
"type": "version_conflict_engine_exception",
"reason": "[23]: version conflict, document already exists (current version [1])",
"index_uuid": "1xWdHLTaTm6l6HbqACaIEA",
"shard": "0",
"index": "ss"
},
"status": 409
}
获取文档
GET /my_index/_doc/1
更新文档
原来的字段会保留,更新age字段
POST /my_index/_update/1
{
"doc": {
"age": 31
}
}
删除文档
DELETE /my_index/_doc/1
``
#### 查询所有文档
```json
GET /my_index/_search
{
"query": {
"match_all": {}
}
}
这个是《老杨玩搜索》里面的总结的图,可以当作“小抄”来记忆。
_bulk API用于在一次请求中执行多个索引、删除和更新操作。这对于批量处理大规模数据特别有用,可以显著提高性能和效率。以下是如何使用_bulk API的基本知识和示例:
POST /my_index/_bulk
{ "index": { "_id": "1" } }
{ "name": "John Doe", "age": 30, "occupation": "Engineer" }
{ "index": { "_id": "2" } }
{ "name": "Jane Doe", "age": 25, "occupation": "Designer" }
{ "update": { "_id": "1" } }
{ "doc": { "age": 31 } }
_bulk API的请求体由多个操作和文档组成。每个操作行包含一个动作描述行和一个可选的源文档行。动作描述行指明了操作的类型(例如,index、create、delete、update)以及操作的元数据。源文档行则包含了实际的数据。
每个操作之间需要用换行符分隔,并且请求体最后必须以换行符结尾。
POST _bulk
{ "index": {"_index":"a" ,"_id": "1" } }
{ "name": "John Doe", "age": 30, "occupation": "Engineer" }
{ "index": {"_index":"b" , "_id": "2" } }
{ "name": "Jane Doe", "age": 25, "occupation": "Designer" }
{ "update": {"_index":"a" , "_id": "1" } }
{ "doc": { "age": 31 } }
全文检索
分词器
在Easysearch中,分词器(Analyzer)用于将文本分解为词项(terms),是全文搜索和文本分析的基础。分词器通常由字符过滤器(Character Filters)、分词器(Tokenizer)和词项过滤器(Token Filters)组成。以下是关于ES分词器的详细介绍:
- 字符过滤器(Character Filters):在分词之前对文本进行预处理。例如,去除HTML标签,替换字符等。
- 分词器(Tokenizer):将文本分解为词项(tokens)。这是分词过程的核心。
- 词项过滤器(Token Filters):对词项进行处理,如小写化、去除停用词、词干提取等。
内置分词器
我们一起看下
POST /index/_mapping
{
"properties": {
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}
}
-
POST /index/_mapping
- 这个部分表示要向名为
index
的索引添加或更新映射设置。
- 这个部分表示要向名为
-
“properties”:
properties
定义了索引中文档的字段结构。在这个例子中,定义了一个名为content
的字段。
-
“content”:
- 定义了名为
content
的字段。
- 定义了名为
-
“type”: “text”
type
字段指定content
字段的数据类型为text
。text
类型适用于需要分词和全文搜索的字段。
-
“analyzer”: “ik_max_word”
analyzer
字段指定索引时使用的分词器为ik_max_word
。ik_max_word
是IK分词器中的一种,它会尽可能多地将文本分解为更多的词项。
-
“search_analyzer”: “ik_smart”
search_analyzer
字段指定搜索时使用的分词器为ik_smart
。ik_smart
是IK分词器中的另一种,它会更智能地进行分词,以提高搜索的准确性。
当然,在设置这个mapping的时候可以使用同样的分词器,也可以使用不同的分词器。这里介绍下IK分词器:
- IK分词器是一种中文分词器,适用于中文文本的分词。IK分词器有两种分词模式:
ik_max_word
和ik_smart
。ik_max_word
:将文本尽可能多地切分成词项,适用于需要更高召回率的场景。ik_smart
:进行最智能的分词,适用于需要更高精度的搜索场景。
这个DSL的设置意味着,在向这个索引添加或更新文档时,content
字段的文本会使用ik_max_word
分词器进行分词处理,以确保文本被尽可能多地切分成词项。而在搜索时,content
字段的文本会使用ik_smart
分词器进行分词处理,以提高搜索的准确性和相关性。
以下是关于standard,ik_smart,ik_max_word这几个分词器的对比:
GET /_analyze
{
"tokenizer": "standard",
"text": "我,机器人"
}
GET /_analyze
{
"tokenizer": "ik_smart",
"text": "我,机器人"
}
GET /_analyze
{
"tokenizer": "ik_max_word",
"text": "我,机器人"
}
结果如下:
# GET /_analyze (standard)
{
"tokens": [
{
"token": "我",
"start_offset": 0,
"end_offset": 1,
"type": "<IDEOGRAPHIC>",
"position": 0
},
{
"token": "机",
"start_offset": 2,
"end_offset": 3,
"type": "<IDEOGRAPHIC>",
"position": 1
},
{
"token": "器",
"start_offset": 3,
"end_offset": 4,
"type": "<IDEOGRAPHIC>",
"position": 2
},
{
"token": "人",
"start_offset": 4,
"end_offset": 5,
"type": "<IDEOGRAPHIC>",
"position": 3
}
]
}
# GET /_analyze(ik_smart)
{
"tokens": [
{
"token": "我",
"start_offset": 0,
"end_offset": 1,
"type": "CN_CHAR",
"position": 0
},
{
"token": "机器人",
"start_offset": 2,
"end_offset": 5,
"type": "CN_WORD",
"position": 1
}
]
}
# GET /_analyze (ik_max_word)
{
"tokens": [
{
"token": "我",
"start_offset": 0,
"end_offset": 1,
"type": "CN_CHAR",
"position": 0
},
{
"token": "机器人",
"start_offset": 2,
"end_offset": 5,
"type": "CN_WORD",
"position": 1
},
{
"token": "机器",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 2
},
{
"token": "人",
"start_offset": 4,
"end_offset": 5,
"type": "CN_CHAR",
"position": 3
}
]
}
如果使用了不存在的分词器会出现这个错误。
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "failed to find global tokenizer under [simple]"
}
],
"type": "illegal_argument_exception",
"reason": "failed to find global tokenizer under [simple]"
},
"status": 400
}