注意
内容不全,这是观看中文文档进行操作的
文档地址
旧版中文文档,部分内容过期 https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
基础入门
你知道的,为了搜索…
索引员工文档
- megacorp 索引名称 -> 数据库
- employee 类型名称 -> 表
- 1 特定雇员的ID -> 主键
- 请求体 JSON文档 -> 行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24PUT /megacorp/employee/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
PUT /megacorp/employee/2
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
PUT /megacorp/employee/3
{
"first_name" : "Douglas",
"last_name" : "Fir",
"age" : 35,
"about": "I like to build cabinets",
"interests": [ "forestry" ]
}要对text类型执行聚合,需要设置
"fielddata":true
1
2
3
4
5
6
7
8
9PUT megacorp/employee/_mapping
{
"properties": {
"interests":{
"type": "text",
"fielddata": true
}
}
}
检索文档
根据索引 类型 id查询指定文档
1 | GET /megacorp/employee/1 |
结果
1 | { |
轻量搜索
根据索引 类型查询全部文档
1 | GET /megacorp/employee/_search |
结果
1 | { |
使用查询表达式搜索
查询
last_name=smith
1 | GET /megacorp/employee/_search |
结果
1 | ... |
更复杂的搜索
查询
last_name=smith and age>30
1 | GET /megacorp/employee/_search |
结果
1 | ... |
全文检索
查询
about
中含有词rock
climbing
根据匹配得分_score
进行排序
1 | GET /megacorp/employee/_search |
结果
1 | ... |
短语搜索
仅匹配”about”中含有”rock climbing”短语
根据匹配得分”_score”进行排序
1 | GET /megacorp/employee/_search |
结果
1 | ... |
高亮搜索
根据匹配得分”_score”进行排序
在”highlight”中使用”em”标签封装了”about”中匹配到的词
1 | GET /megacorp/employee/_search |
结果
1 | ... |
分析
按照”interests”进行分组
1 | GET /megacorp/employee/_search |
结果
1 | ... |
查询 last_name=smith 并按照”interests”中的内容进行分组
1 | GET /megacorp/employee/_search |
结果
1 | ... |
先聚合桶再进行度量
1 | GET /megacorp/employee/_search |
结果
1 | ... |
集群内的原理
集群健康
1 | GET /_cluster/health |
结果
①
- green 所有的主分片和副本分片都正常运行。
- yellow 所有的主分片都正常运行,但不是所有的副本分片都正常运行。
- red 有主分片没能正常运行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17{
"cluster_name": "docker-cluster",
"status": "yellow",//①
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 23,
"active_shards": 23,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 20,
"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": 53.48837209302325
}添加索引
1
2
3
4
5
6
7PUT /blogs
{
"settings" : {
"number_of_shards" : 3,//分片
"number_of_replicas" : 1//副本
}
}数据输入和输出
文档元数据
- _index 放在哪个数据库
这个名字必须小写,不能以下划线开头,不能包含逗号
- _type 放在哪个表
可以是大写或者小写,但是不能以下划线或者句号开头,不应该包含逗号,并且长度限制为256个字符
- _id 文档唯一标识
字符串类型,不指定会自动生成
索引文档
指定id创建文档
1
2
3
4
5
6PUT /website/blog/123
{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}不指定id创建文档
1
2
3
4
5
6PUT /website/blog
{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}
取回一个文档
1 | GET website/blog/123 |
结果
1 | { |
只返回原始文档
_source
1 | GET website/blog/123/_source |
结果
1 | { |
检查文档是否存在
使用
HEAD
代替GET,只返回请求头,没有请求体
1 | HEAD /website/blog/123 |
返回 200 - OK
1 | HEAD /website/blog/124 |
返回 404 - Not Found
更新整个文档
存在,整个文档替换
不存在,就创建一个新文档
1 | PUT /website/blog/123 |
创建新文档
加参数 存在不能创建
1 | POST /website/blog/123?op_type=create |
等同于
下面
1 | POST /website/blog/123/_create |
都是返回 结果
1 | { |
不加参数
1 | POST /website/blog/111 |
不存在 创建
result
是created
,_version
是1
1 | { |
存在 更新
result
是updated
,_version
加1
1 | { |
删除文档
1 | DELETE /website/blog/123 |
已存在 结果
result
为deleted
1 | { |
不存在 结果
result
为not_found
1 | { |
处理冲突
两个人在购买同一种物品,原库存100,A读取到,B也读取到,B买了一件这个商品,
此时商品库存为99,但是B读取到的是100,B买了一件之后还是99,就形成了冲突
悲观锁
我修改之后,别人才可以修改乐观锁
假设不可以冲突,如果读取的时候被修改,就更新失败
elasticsearch就是使用乐观锁
乐观并发控制
创建一篇文章
1 | PUT /website/blog/888/_create |
获取数据
1 | GET /website/blog/888 |
结果,其中_version
就是版本号
1 | { |
现在修改文档,指定版本号为当前版本号1
1 | PUT /website/blog/888?version=1 |
结果 修改成功 _version
版本号+1 result
为updated
1 | { |
如果仍然执行上面
version=1
结果 修改失败 因为需要指定version
等于当前版本号才可以修改
1 | { |
但是我们可以使用
version_type
指定external
来设置
但是指定的version
要大于当前版本号,小于等于都不可以
1 | PUT /website/blog/888?version=99&version_type=external |
结果 修改成功 版本号也改为了99
1 | { |
文档的部分更新
先添加一篇文章
1 | PUT /website/blog/3/_create |
使用POST请求加上参数
_update
来对doc
添加指定更新
如果doc
中指定属性不存在则添加
如果存在 age=26 又改为 age=27 则会更新成功
如果存在 age=27 又改为 age=27 则会不进行更新返回result
为noop
如果为多个字段 例如 age=27 and sex=man 更新其中任何一个就可以更新成功
1 | POST /website/blog/3/_update |
结果 更新成功 版本号+1 result
为updated
1 | { |
检索
GET /website/blog/3
1 | { |
取回多个文档
查询
website/blog/2
website/blog/1
website/pageviews/1
1 | GET /_mget |
结果
1 | { |
查询 id为2 1 55
1 | GET /website/blog/_mget |
结果
1 | { |
代价较小的批量操作
- 每个操作都是独立的,互不影响
bulk允许多次 create,index,update,delete
create
成功201 失败409index
成功201update
成功200 失败404 _id不存在delete
成功200 失败404 _id不存在改进 都是操作同一个索引 类型1
2
3
4
5
6
7
8
9
10POST _bulk
{ "create": { "_index": "website", "_type": "blog", "_id": "1" }}
{ "title": "My first blog post" }
{ "create": { "_index": "website", "_type": "blog", "_id": "2" }}
{ "title": "My first blog post" }
{ "index": { "_index": "website", "_type": "blog"}}
{ "title": "My first blog post" }
{ "delete": { "_index": "website", "_type": "blog", "_id": "1" }}
{ "update":{ "_index": "website", "_type": "blog", "_id": "2" }}
{"doc":{"content":"I'm content...."}}1
2
3
4
5
6
7
8
9
10POST /website/blog/_bulk
{ "create": {"_id": "1" }}
{ "title": "My first blog post" }
{ "create": {"_id": "2" }}
{ "title": "My first blog post" }
{ "index": {}}
{ "title": "My first blog post" }
{ "delete": {"_id": "1" }}
{ "update":{"_id": "2" }}
{"doc":{"content":"I'm content...."}}
搜索——最基本的工具
多索引,多类型
1 | //查找所有索引的所有文档 |
分页
size
默认10 代表”hits”数组显示的数量,最小为0,大于等于”total”都会显示全部from
默认0 代表要跳过几条例如
一共五条 size=2 from=1 则只会显示第2 3两条数据
1 | GET _search |
映射和分析
映射
获取映射
1 | GET cars/transactions/_mapping |
结果
1 | { |
- 字符串类型
text
可分词,不可聚合keyword
可聚合,不可分词
- 基本数值类型
- long、interger、short、byte、double、float、half_float
- 日期类型
- date 建议存为 long类型
创建映射字段
设置"index": "false"
不能对该字段进行搜索text
类型默认会进行分词,也可以指定分词器"analyzer": "分词器"
text
想设置聚合需要设置"fielddata": true
,或【使用xxx.keyword,而不是使用xxx】1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16PUT 索引/类型/_mapping/
{
"properties": {
"字段名称": {
"type": "text",
"analyzer": "ik_max_word"
},
"字段名称": {
"type": "keyword",
"index": "false"
},
"字段名称": {
"type": "float"
}
}
}查看映射关系
1
GET 索引/类型/_mapping
删除索引
1
DELETE 索引
- date 建议存为 long类型
请求体查询
查询表达式
查询全部索引的全部类型
请求体为空可以省略
全部索引 _all 可以省略
1 | GET _search |
1 | GET _search |
1 | GET _search |
1 | GET _all/_search |
指定索引 类型查询
可以表示零个或多个,cars
可以匹配`caar
*s`
查询多个索引的全部类型的全部文档
1 | GET 索引1,索引2/_search |
查询多个索引的多个类型的全部文档
1 | GET 索引1,索引2/类型1,类型2/_search |
查询
price=15000
1 | GET cars/transactions/_search |
最重要的查询
match_all
默认的查询,匹配所有文档
1 | GET a1/student/_search |
结果
1 | { |
match
查询text
类型会分词查询字符串
数组,日期,布尔或not_analyzed
字符串字段,就会精准匹配
1 | { "match": { "tweet": "About Search" }} |
1 | //测试笔记 |
multi_match
多字段搜索name like '%大米%' or f1 like '%大米%'
1 | GET a1/student/_search |
range
查询10<=age<=20
lt <
lte <=
gt >
gte >=
1 | GET a1/student/_search |
term
精准匹配
1 | GET a1/student/_search |
terms
多值匹配,满足一个即可
1 | GET a1/student/_search |
exists
查询存在指定字段的文档
1 | GET a1/student/_search |
组合多查询
与
must
[{1},{2}] 满足所有
查询”name”分词有”小米”并且”age”等于11或者22
1 | GET a1/_search |
非
must_not
[{1},{2}] 不满足所有
查询”name”分词没有”小米并且”age”不等于11或者22
1 | GET a1/_search |
或
should
[{1},{2}] 满足任意一个
1 | GET a1/_search |
结果过滤
1 | 查询字段只显示 name age |
过滤
filter
会将评分设置为0,不会使评分对结果影响
查询”name”=小米并且10<=age<=20
1 | GET a1/_search |
排序与相关性
排序
排序
查询”name”=小米并按照年龄降序
1 | GET a1/_search |
多字段排序 先排序第一个,第一个相同才会对第二个进行排序
1 | GET a1/_search |
什么是相关性?
检索词频率
一个词出现次数多相关性越高反向文档频率
一个词只在一个文档中存在,相关性高,如果在十个文档中存在,相关性低字段长度准则
“a”在”ab”中相关性比在”abcd”中要高,长度越短越高索引管理
创建一个索引
手动创建索引
1
2
3
4
5
6
7
8PUT 索引名
{
"settings":{...},
"mappings":{
"类型名称1":{...},
"类型名称2":{...}
}
}设置禁止自动创建索引
找到config/elasticsearch.yml
在每个节点下添加action.auto_create_index: false
删除一个索引
删除指定索引
DELETE /my_index
删除多个索引
DELETE /index_one,index_two
DELETE /index_*
+删除全部索引
DELETE /_all
DELETE /*
如果不想使用 _all 或 * 来批量删除索引
设置elasticsearch.yml
配置action.destructive_requires_name: true
索引设置
number_of_shards
分片默认5number_of_replicas
副本默认1
1 | PUT /my_temp_index |
可以修改副本,不能修改分片
1 | PUT /my_temp_index/_settings |
索引别名
创建一个索引
g
1 | PUT g |
查看
g
1 | GET g |
结果 此时索引别名aliases
为空
1 | { |
创建一个别名
g1
1 | PUT g/_alias/g1 |
此时执行
GET g
或GET g1
是一样的效果,返回
1 | { |
批量操作
指定g
删除别名g1
指定g
添加别名g2
指定g
添加别名g3
1 | POST _aliases |
结果
1 | { |
深入搜索
结构化搜索
精确值查找
先设置类型,设置
productID
不分词,可以精确查找
1 | PUT my_store/products/_mapping |
添加数据
1 | POST /my_store/products/_bulk |
精确查找
price=20
1 | GET my_store/products/_search |
不希望评估计算,进行排除,包括的计算
这样做可以优化速度,统计评分设置 1
1 | GET /my_store/products/_search |
查询
productID=XHDK-A-1293-#fJ3
1 | GET /my_store/products/_search |
组合过滤器
布尔过滤器
boolmust
:[{1},{2}] 都满足and
must_not
:[{1},{2}] 都不满足not
should
:[{1},{2}] 满足一个即可or
组合
(price=20 or productID=XHDK-A-1293-#fJ3) and price!=30
1 | GET /my_store/products/_search |
嵌套
price=30 and (productID!=JODL-X-1937-#pV7)
1 | GET my_store/products/_search |
查找多个精确值
查找
price in (20,30)
1 | GET /my_store/products/_search |
范围
数值范围
price BETWEEN 20 AND 40
>=20 AND <=40
1 | GET /my_store/products/_search |
日期范围
定义日期类型
1 | PUT my_store |
插入数据
1 | POST /my_store/products/_bulk |
可以使用
now
表示当前时间
因为我们定义格式为”yyyy-MM-dd HH:mm:ss” 所有y M d H m s
表示年月日时分秒
查询
date
大于等于当前时间的上一个月
1 | GET my_store/products/_search |
指定时间 查询大于”2019-09-10 11:11:11”
1 | GET my_store/products/_search |
处理null值
查询存在
date
字段的文档,并且date IS NOT NULL
1 | GET my_store/products/_search |
全文检索
写到这里,就不往下写了,这时我去看
7.4
的官方文档了