Elasticsearch教程TabTan
这篇笔记记录于2021年8月,一些基本操作。迁移至此,分享给需要它的人。
快速开始
索引
员工案例
保存
对于员工目录,我们将做如下操作:
- 每个员工索引一个文档,文档包含该员工的所有信息。
- 每个文档都将是
employee
类型 。 - 该类型位于 索引
megacorp
内。 - 该索引保存在我们的 Elasticsearch 集群中。
实践中这非常简单(尽管看起来有很多步骤),我们可以通过一条命令完成所有这些动作:
PUT /megacorp/employee/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
curl -X PUT "101.201.125.13:9200/test/user/1?pretty" -H 'Content-Type: application/json' -d'
{
"first_name" : "三",
"last_name" : "唐",
"age" : 25,
"about" : "佛祖有泪 观音泪",
"interests": [ "Rap", "music" ]
}
'
注意,路径 /megacorp/employee/1
包含了三部分的信息:
-
megacorp
索引名称
-
employee
类型名称
-
1
特定雇员的ID
索引文档
GET /megacorp/employee/1
curl -X GET "localhost:9200/megacorp/employee/1?pretty"
将 HTTP 命令由
PUT
改为GET
可以用来检索文档,同样的,可以使用DELETE
命令来删除文档,以及使用HEAD
指令来检查文档是否存在。如果想更新已存在的文档,只需再次PUT
。
轻量搜索
索引全部
GET /megacorp/employee/_search
curl -X GET "localhost:9200/megacorp/employee/_search?pretty"
索引带条件
GET /megacorp/employee/_search?q=last_name:唐
# or
curl -X GET "localhost:9200/megacorp/employee/_search?q=last_name:Smith&pretty"
_search
表示轻量索引,q=
表示索引条件
查询表达式搜索
Query-string 搜索通过命令非常方便地进行临时性的即席搜索 ,但它有自身的局限性(参见 轻量 搜索 )。Elasticsearch 提供一个丰富灵活的查询语言叫做 查询表达式 , 它支持构建更加复杂和健壮的查询。
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}
# or for curl
curl -X GET "localhost:9200/megacorp/employee/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}
'
返回结果与之前的查询一样,但还是可以看到有一些变化。其中之一是,不再使用 query-string 参数,而是一个请求体替代。这个请求使用 JSON 构造,并使用了一个
match
查询(属于查询类型之一,后面将继续介绍)。
复杂搜索
现在尝试下更复杂的搜索。 同样搜索姓氏为 唐 的员工,但这次我们只需要年龄大于 18 的。查询需要稍作调整,使用过滤器 filter ,它支持高效地执行一个结构化查询。
GET /megacorp/employee/_search
{
"query" : {
"bool": {
"must": {
"match" : {
"last_name" : "唐"
}
},
"filter": {
"range" : {
"age" : { "gt" : 18 }
}
}
}
}
}
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.24116206,
"hits" : [
{
"_index" : "megacorp",
"_type" : "employee",
"_id" : "3",
"_score" : 0.24116206,
"_source" : {
"first_name" : "三藏",
"last_name" : "唐",
"age" : 42,
"about" : "观音我来了 阿弥陀佛",
"interests" : [
"forestry"
]
}
}
]
}
}
全文搜索
GET /megacorp/employee/_search
{
"query":{
"match": {
"first_name": "三"
}
}
}
根据匹配度排序的全文查询
短语搜索
match_phrase
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "三"
}
}
}
100%匹配 所有短语中存在三的才行
高亮搜索
许多应用都倾向于在每个搜索结果中 高亮 部分文本片段,以便让用户知道为何该文档符合查询条件。在 Elasticsearch 中检索出高亮片段也很容易。
再次执行前面的查询,并增加一个新的 highlight
参数:
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"first_name" : "三"
}
},
"highlight": {
"fields" : {
"first_name" : {}
}
}
}
当执行该查询时,返回结果与之前一样,与此同时结果中还多了一个叫做 highlight
的部分。这个部分包含了 about
属性匹配的文本片段,并以 HTML 标签 <em></em>
封装:
分析
终于到了最后一个业务需求:支持管理者对员工目录做分析。 Elasticsearch 有一个功能叫聚合(aggregations),允许我们基于数据生成一些精细的分析结果。聚合与 SQL 中的 GROUP BY
类似但更强大。
字段优化
# 字段优化
PUT /megacorp/employee/_mapping?include_type_name=true
{
"properties": {
"interests": {
"type": "text",
"fielddata": true
}
}
}
聚合索引
GET /megacorp/employee/_search
{
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}
{
"took" : 163,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "megacorp",
"_type" : "employee",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"first_name" : "培正",
"last_name" : "谈",
"age" : 18,
"about" : "不要迷恋哥 哥只是个传说",
"interests" : [
"唱",
"Rap",
"跳",
"篮球"
]
}
},
{
"_index" : "megacorp",
"_type" : "employee",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"first_name" : "三",
"last_name" : "唐",
"age" : 16,
"about" : "观音有泪",
"interests" : [
"forestry"
]
}
},
{
"_index" : "megacorp",
"_type" : "employee",
"_id" : "3",
"_score" : 1.0,
"_source" : {
"first_name" : "三藏",
"last_name" : "唐",
"age" : 42,
"about" : "观音我来了 阿弥陀佛",
"interests" : [
"forestry"
]
}
}
]
},
"aggregations" : {
"all_interests" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "forestry",
"doc_count" : 2
},
{
"key" : "rap",
"doc_count" : 1
},
{
"key" : "唱",
"doc_count" : 1
},
{
"key" : "球",
"doc_count" : 1
},
{
"key" : "篮",
"doc_count" : 1
},
{
"key" : "跳",
"doc_count" : 1
}
]
}
}
}
集群
集群健康
GET /_cluster/health
{
"cluster_name" : "docker-cluster",
"status" : "yellow",
"timed_out" : false,
"number_of_nodes" : 1,
"number_of_data_nodes" : 1,
"active_primary_shards" : 10,
"active_shards" : 10,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 1,
"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" : 90.9090909090909
}
status
字段指示着当前集群在总体上是否工作正常。它的三种颜色含义如下:
green
所有的主分片和副本分片都正常运行。
yellow
所有的主分片都正常运行,但不是所有的副本分片都正常运行。
red
有主分片没能正常运行。在本章节剩余的部分,我们将解释什么是 主 分片和 副本 分片,以及上面提到的这些颜色的实际意义。
分片
PUT /blogs
{
"settings" : {
"number_of_shards" : 2,
"number_of_replicas" : 1
}
}
创建了一个blogs索引,其中包含2个主分片,每个主分片包含一个副本分片
集群的健康状况为
yellow
则表示全部 主 分片都正常运行(集群可以正常服务所有请求),但是 副本 分片没有全部处在正常状态。 实际上,所有3个副本分片都是unassigned
—— 它们都没有被分配到任何节点。 在同一个节点上既保存原始数据又保存副本是没有意义的,因为一旦失去了那个节点,我们也将丢失该节点上的所有副本数据。当前我们的集群是正常运行的,但是在硬件故障时有丢失数据的风险。
更多扩容
在运行中的集群上是可以动态调整副本分片数目的,我们可以按需伸缩集群。让我们把副本数从默认的 1
增加到 2
:
PUT /blogs/_settings
{
"number_of_replicas" : 2
}
语法
只搜索部分
GET /megacorp/employee/1?_source=first_name
{
"_index" : "megacorp",
"_type" : "employee",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"first_name" : "培正"
}
}
-
/_search
在所有的索引中搜索所有的类型
-
/gb/_search
在
gb
索引中搜索所有的类型 -
/gb,us/_search
在
gb
和us
索引中搜索所有的文档 -
/g*,u*/_search
在任何以
g
或者u
开头的索引中搜索所有的类型 -
/gb/user/_search
在
gb
索引中搜索user
类型 -
/gb,us/user,tweet/_search
在
gb
和us
索引中搜索user
和tweet
类型 -
/_all/user,tweet/_search
在所有的索引中搜索
user
和tweet
类型
当在单一的索引下进行搜索的时候,Elasticsearch 转发请求到索引的每个分片中,可以是主分片也可以是副本分片,然后从每个分片中收集结果。多索引搜索恰好也是用相同的方式工作的—只是会涉及到更多的分片。
分页
SQL 使用 LIMIT
关键字返回单个 page
结果的方法相同,Elasticsearch 接受 from
和 size
参数:
-
size
显示应该返回的结果数量,默认是
10
-
from
显示应该跳过的初始结果数量,默认是
0
GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10
# or for curl
curl -X GET "localhost:9200/_search?size=5&pretty"
curl -X GET "localhost:9200/_search?size=5&from=5&pretty"
curl -X GET "localhost:9200/_search?size=5&from=10&pretty"