注:
- 该文档中对于API的调用都通过Kibana进行调用
- 该文档中 _doc 作为默认的类型
前置知识
- 9300端口是Elasticsearch集群间组件通信端口,而9200端口是浏览器访问的HTTP协议的Restful端口
- elasticsearch是面向文档的数据库,且一切都是JSON
Index 索引
一个索引由一个名字来标识(必须全部是小写字母),并且当我们要对这个索引中的文档进行索引、搜索、更新和删除(CRUD)的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。
Elastic 会索引所有字段,经过处理后写入一个反向索引(Inverted Index)。查找数据的时候,直接查找该索引。
所以,Elastic 数据管理的顶层单位就叫做 Index(索引)。它是单个数据库的同义词。每个 Index (即数据库)的名字必须是小写。
下面的命令可以查看当前节点的所有 Index:
GET /_cat/indices?v
Elasticsearch 索引的精髓:一切设计都是为了提高搜索的性能。
Document 文档
在Index里面,单条记录(行)成为Document(文档),多个Document构成一个Index。
Document使用了JSON格式表示,如下:
{ "user": "张三", "title": "工程师", "desc": "数据库管理" }
同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。
Relational DB | ElasticSearch |
数据库(database) | 索引(indices) |
表(tables) | types 会被弃用 |
行(rows) | documents |
字段(columns) | fields |
elasticsearch(集群)中可以包含多个索引(数据库) ,每个索引中可以包含多个类型(表) ,每个类型下又包含多个文档(行) ,每个文档中又包含多个字段(列)。
映射 Mapping
mapping 是数据处理的方式和规则方面做一些限制,如:某个字段的数据类型、默认值、分析器、是否被索引等等。这些都是映射里面可以设置的,其它就是处理 ES 里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好。
Rest风格
基本规则
method | url地址 | 描述 |
PUT(创建,修改) | localhost:9200/索引名称/_doc/文档id | 创建文档(指定文档id) |
POST(创建) | localhost:9200/索引名称/_doc | 创建文档(随机文档id) |
POST(修改) | localhost:9200/索引名称/_update/文档id | 修改文档 |
DELETE(删除) | localhost:9200/索引名称/_doc/文档id | 删除文档 |
GET(查询) | localhost:9200/索引名称/_doc/文档id | 查询文档通过文档ID |
GET | POST(查询) | localhost:9200/索引名称/_search/文档id | 查询所有数据 |
REST API:REST APIs | Elasticsearch Guide [7.5] | Elastic
查看Elasticsearch信息
GET _cat/indices
GET _cat/aliases
GET _cat/allocation
GET _cat/count
GET _cat/fielddata
GET _cat/health
GET _cat/indices
GET _cat/master
GET _cat/nodeattrs
GET _cat/nodes
GET _cat/pending_tasks
GET _cat/plugins
GET _cat/recovery
GET _cat/repositories
GET _cat/segments
GET _cat/shards
GET _cat/snapshots
GET _cat/tasks
GET _cat/templates
GET _cat/thread_pool
操作索引 Index
新建 PUT
直接项Elastic服务器发出 PUT 请求。如创建一个 weather 的 Index:
PUT /{索引名}
------------
PUT /weather
如果操作成功时,将会返回一个JSON对象,里面的 acknowledged 字段表示操作成功:
{ "acknowledged":true, "shards_acknowledged":true }
指定字段的类型
Elasticsearch中有着以下字段数据类型:
- 字符串类型
-
- text:支持分词,全文检索,支持模糊、精确查询,不支持聚合,排序操作;text类型的最大支持的字符长度无限制,适合大字段存储;
- keyword:不进行分词,直接索引、支持模糊、支持精确匹配,支持聚合、排序操作。keyword类型的最大支持的长度为——32766个UTF-8类型的字符,可以通过设置 ignore_above 指定自持字符长度,超过给定长度后的数据将不被索引,无法通过term精确匹配检索返回结果。
- 数值型
-
- long、Integer、short、byte、double、float、half float、scaled float
- 日期类型
-
- date
- 布尔类型
-
- boolean
- 二进制类型
-
- binary
- 等等…
创建 Index 时能够通过 mappings 指定文档字段的类型:
PUT /test
{
"mappings": {
"properties": { # 表示字段集
"name": { # 配置对应字段名称的类型
"type": "text", # 配置类型
"analyzer": "ik_max_word" # 指定分词器
},
"value": {
"type": "long"
}
}
}
}
追加字段
如果需要在已存在的文档中追加字段可以通过 PUT 来追加
PUT /account/_mapping
{
"properties": {
"gender": {
"type": "long"
}
}
}
查看索引详情 GET
基于上面指定字段类型添加Index后,通过 GET 即可查看索引详情:
GET /{索引名}
------------
GET /test
查看索引映射信息
GET /account/_mapping
删除 DELETE
发送一个 DELETE 请求,即可删除指定 Index,如删除 weather:
DELETE /{索引名}
------------
DELETE /weather
** 操作文档 Document
新增 Document
有两种方式,分别是PUT和POST:
1、PUT
PUT /{索引名}/_doc/{文档 ID}
{ ... } # 字段
------------
PUT /test3/_doc/1
{
"name": "何妨"
}
2、POST
POST /{索引名}/_doc
{ ... } # 字段
------------
POST /test3/_doc
{
"name": "何妨"
}
相同点:
- 在 Index 不存在时,都会创建对应的 Index
不同点:
- PUT 需要指定文档 ID,而 POST 文档 ID 则是随机生成
更新文档 Document
存在两种方案,如:
1、PUT
- version 会 +1
- 直接替换文档所有值,如果有字段漏写,将会丢失该字段
PUT /{索引名}/_doc/{文档 ID}
{ ... } # 字段
------------
PUT /test3/_doc/1
{
"name": "何妨",
"age": 25
}
GET /test3/_doc/1
# 会对原数据直接覆盖,导致 age 字段丢失
PUT /test3/_doc/1
{
"name": "何妨"
}
GET /test3/_doc/1
2、POST
- 如果字段值和文档的值一样,则 version 不变
- 注意需要写在 doc 属性里面
- 只更新指定的字段
POST /{索引名}/_update/{文档 ID}
{
"doc": {...} # 字段
}
------------
PUT /test3/_doc/1
{
"name": "何妨",
"age": 25
}
GET /test3/_doc/1
# 只更新 age 字段
POST /test3/_update/1
{
"doc": {
"age": 18
}
}
GET /test3/_doc/1
删除文档 DELETE
DELETE /{索引名}/_doc/{文档 ID}
------------
DELETE /test3/_doc/1
**** 文档查询
数据准备
PUT /account
{
"mappings": {
"properties": {
"username": {
"type": "keyword"
}
}
}
}
PUT /account/_doc/1
{
"name": "何妨",
"username": "jayin",
"password": "123456",
"desc": "独自归去又何妨",
"tags": ["程序员", "直男"]
}
PUT /account/_doc/2
{
"name": "往事随风",
"username": "wssuifeng",
"password": "123456",
"desc": "我吹过你吹过的晚风",
"tags": ["大长腿", "暖男"]
}
PUT /account/_doc/3
{
"name": "洪哥",
"username": "chenghong",
"password": "123456",
"desc": "我是独一无二的",
"tags": ["异次元", "小可爱"]
}
PUT /account/_doc/4
{
"name": "何老师",
"username": "jayin123",
"password": "123456",
"desc": "独自归去又何妨",
"tags": ["程序员", "直男"]
}
简单查询
GET /{索引名}/_search?q={字段}:{值}
------------
GET /account/_search?q=name:何
GET /account/_search?q=username:jayin
注意:
- 查询时如果对应字段类型为 text ,那么将会采用 分词匹配查询
- 如果类型为 keyword,则不会使用分词匹配查询,而是全等查询
***** 复杂查询 query
*** match 分词匹配
match 会使用 分词器 进行分词解析
- 默认查询
GET /account/_search
{
"query": {
"match": {
"name": "何妨"
}
}
}
效果同 GET /account/_search?q=name:何妨
- 多值匹配
如果需要匹配多个值时,可以用 ' ' 空格隔开
GET /account/_search
{
"query": {
"match": {
"name": "何 风"
}
}
}
运行结果:
** match_phrase 整体匹配的模糊查询
match_phrase 匹配有以下规则:
- match_phrase也是采用分词
- 目标文档需要包含分词后的所有词
- 目标文档还要保持这些词的相对顺序和文档中的一致
GET /account/_search
{
"query": {
"match_phrase": {
"desc": "吹过的晚"
}
}
}
运行结果:
也就是说,match_phrase 严格要求 文档中的值分词后关键字的顺序 和 查询值中分词后的顺序相对一样
** term 精确查询
term 不会对查询条件中的字段值进行分词操作,而是直接拿来与文档中对应字段进行全等匹配。
但如果字段类型为 text 时,仍会被分词建立倒排索引,并通过倒排索引查找。适用于 number、date、keyword等查询,不适合 text
GET /account/_search
{
"query": {
"term": {
"name": "何 "
}
}
}
-------------------
term 会把 '何 ' 看出一个整体进行查询,如果是match的话则会被分词器处理为 '何'
** terms 多值精确查询
GET /account/_search
{
"query": {
"terms": {
"age": [
"23",
"24"
]
}
}
}
------------------- 功能同下
GET /account/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"age": 23
}
}, {
"term": {
"age": 24
}
}
]
}
}
}
运行结果:
**** fuzzy 模糊查询
GET /account/_search
{
"query": {
"fuzzy": {
"name": {
"value": "何妨",
"fuzziness": 1
}
}
}
}
查询结果:
该查询可以按编辑距离(fuzziness),进行匹配查询。如:
何妨 进行分词后:何妨
如果是使用 match 查询时,只能够查询出 对应字段分词后包含“何妨”的文档
但在 fuzzy 中,则可以根据 编辑距离 进行查询,如将会查询:何妨、何、妨
所以,在索引中对应字段分词后包含 上面 三种的都会查到
*** 全查询
查出所有文档
GET /account/_search
{
"query": {
"match_all": {}
}
}
------------------ 同下
GET /account/_search
{}
*** _source 字段过滤
GET /account/_search
{
"query": {
"match": {
"name": "何妨"
}
},
"_source": ["name", "username", "desc"]
}
查询结果只列出在 _source 中指定的字段
** sort 排序
GET /account/_search
{
"sort": [
{
"age": {
"order": "desc"
},
"birth": {
"order": "asc"
}
}
]
}
-------------------- 上面那种优先级比较高
GET /account/_search
{
"sort": [
{
"age": {
"order": "desc"
}
},
{
"birth": {
"order": "asc"
}
}
]
}
注意,sort不支持对 text 和 keyword 进行排序
*** from、size 分页 (效率低下)
- from:从第几条记录开始
- size:查多少条
可以理解为 LIMIT {from}, {size}
GET /account/_search
{
"sort": [
{
"age": {
"order": "desc"
}
}
],
"from": 2,
"size": 1
}
*** bool 多条件查询
- must:多条件查询,相当于 and,值是一个数组
GET /account/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "何妨"
}
}, {
"match": {
"username": "jayin"
}
}
]
}
}
}
---------------
WHERE name LIKE '%何妨%' AND username = 'jayin'
在 must 中的条件属于并列条件,所以 bool 里面的 must 属于多条件查询
- should:满足其一即可,相当于 or ,值是数组
GET /account/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"name": "何妨"
}
}, {
"match": {
"username": "chenghong"
}
}
]
}
}
}
------------------
WHERE name LIKE '%何妨%' OR username = 'chenghong'
should 属于 or 查询,满足其一即可匹配
- must_not:等价于 must 的相反,也就是 ! 查询
- filter:过滤,能够用于范围查询
- gt:大于
- lt:小于
- gte / lte:包含等于
GET /account/_search
{
"query": {
"bool": {
"filter": {
"range": {
"age": {
"gt": 23,
"lt": 25
}
}
}
}
}
}
----------------------
WHERE age > 23 AND age < 25
运行结果:
*** 高亮查询
通过 highlight 可以 设置哪些字段需要高亮,以及高亮标签
GET /account/_search
{
"query": {
"match": {
"name": "何"
}
},
"highlight": {
"pre_tags": "<div class='active'>", // 设置高亮前置标签
"post_tags": "</div>", // 设置高亮后置标签
"fields": {
"name": {} // 标记出需要高亮的字段,这样只有该字段会被高亮处理
}
}
}
**** 聚合查询 aggs
** 分组统计 terms
GET /account/_search
{
"aggs":{ //聚合操作
"age_group":{ //名称,随意起名
"terms":{ //分组
"field":"username" //分组字段
}
}
}
}
运行后会统计相同用户名的数量,运行结果:
可以看到查询结果中还附带了原始数据,如果不需要原始数据可以如下所示:
GET /account/_search
{
"aggs":{
"age_group":{
"terms":{
"field":"username"
}
}
},
"size": 0 // 返回结果数量
}
** 平均值 avg
GET /account/_search
{
"aggs": {
"age_avg": {
"avg": {
"field": "age"
}
}
},
"size": 0
}
除了上面两种外,还有:
- max
- min
- sum
- 等等...
分词分析
GET /_analyze
{
"text": "独自归去又何妨",
"analyzer": "ik_max_word"
}