1 ES简介
1.1 ES技术栈
The Elastic Stack, 包括 Elasticsearch、Kibana、Beats 和 Logstash(也称为 ELK Stack)。能够安全可靠地获取任何来源、任何格式的数据,然后实时地对数据进行搜索、分析和可视化。Elaticsearch,简称为ES, ES是一个开源的高扩展的分布式全文搜索引擎,是整个Elastic Stack技术栈的核心。它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。
1.2 全文搜索引擎
Google,百度类的网站搜索,它们都是根据网页中的关键字生成索引,我们在搜索的时候输入关键字,它们会将该关键字即索引匹配到的所有网页返回;还有常见的项目中应用日志的搜索等等。对于这些非结构化的数据文本,关系型数据库搜索不是能很好的支持。
一般传统数据库,全文检索都实现的很鸡肋,因为一般也没人用数据库存文本字段。进行全文检索需要扫描整个表,如果数据量大的话即使对SQL的语法优化,也收效甚微。建立了索引,但是维护起来也很麻烦,对于 insert 和 update 操作都会重新构建索引。这里说到的全文搜索引擎指的是目前广泛应用的主流搜索引擎。它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。
1.3 正排索引vs倒排索引
正排索引一般指关系型数据库中的索引,把不同的数据存放在不同的字段中,通过索引字段查找数据。
倒排索引的思想是把数据中的关键词提取出来,转换为关键词到数据的映射
1.4 数据格式
Elasticsearch是面向文档型数据库,一条数据在这里就是一个文档。为了方便大家理解,我们将Elasticsearch里存储文档数据和关系型数据库MySQL存储数据的概念进行一个类比ES里的Index可以看做一个库,而Types相当于表,Documents则相当于表的行。这里Types的概念已经被逐渐弱化,Elasticsearch 6.X中,一个index下已经只能包含一个type,Elasticsearch 7.X中, Type的概念已经被删除了。
2 入门使用
2.1 索引操作
2.1.1 创建索引
PUT:http://localhost:9200/user
response:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "user"
}
2.1.2 查询索引
GET:http://localhost:9200/user
response:
{
"user": {
"aliases": {},
"mappings": {},
"settings": {
"index": {
"creation_date": "1618108925731",
"number_of_shards": "1",
"number_of_replicas": "1",
"uuid": "U8Fc9YEHTQSHRVZjm1VoDQ",
"version": {
"created": "7080099"
},
"provided_name": "user"
}
}
}
}
查询全部索引
GET:http://localhost:9200/_cat/indices?v
response:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open user U8Fc9YEHTQSHRVZjm1VoDQ 1 1 0 0 208b 208b
表头 | 含义 |
health | 当前服务器健康状态: green(集群完整) yellow(单点正常、集群不完整) red(单点不正常) |
status | 索引打开、关闭状态 |
index | 索引名 |
uuid | 索引统一编号 |
pri | 主分片数量 |
rep | 副本数量 |
docs.count | 可用文档数量 |
docs.deleted | 文档删除状态(逻辑删除) |
store.size | 主分片和副分片整体占空间大小 |
pri.store.size | 主分片占空间大小 |
2.1.3 删除索引
DELETE:http://localhost:9200/user
2.2 文档操作
2.2.1 创建文档
POST:http://127.0.0.1:9200/user/_doc
request
{
"name":"汤姆",
"age":20,
"hobby":"唱歌,足球,篮球,爬山"
}
response
{
"_index": "user",
"_type": "_doc",
"_id": "ABQIv3gB_sQQDSsOlaVw",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
表头 | 含义 |
_index | 索引 |
_type | 文档 |
_id | 主键,随机生成 |
_version | 版本 |
_result | 操作结果,包括created、updated、deleted |
_shards | total:分片总数,successful:分片成功,failed:分片失败 |
_seq_no |
|
自定义id创建文档
POST:http://127.0.0.1:9200/user/_doc/1
request
{
"name":"杰瑞",
"age":21,
"hobby":"唱歌,跳舞,看电影,追剧"
}
response
{
"_index": "user",
"_type": "_doc",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
2.2.2 查询文档
根据id查询
GET:http://127.0.0.1:9200/user/_doc/1
response
{
"_index": "user",
"_type": "_doc",
"_id": "1",
"_version": 1,
"_seq_no": 1,
"_primary_term": 1,
"found": true,
"_source": {
"name": "杰瑞",
"age": 21,
"hobby": "唱歌,跳舞,看电影,追剧"
}
}
全部查询
GET:http://127.0.0.1:9200/user/_search
{
"took": 69,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "user",
"_type": "_doc",
"_id": "ABQIv3gB_sQQDSsOlaVw",
"_score": 1.0,
"_source": {
"name": "汤姆",
"age": 20,
"hobby": "唱歌,足球,篮球,爬山"
}
},
{
"_index": "user",
"_type": "_doc",
"_id": "1",
"_score": 1.0,
"_source": {
"name": "杰瑞",
"age": 21,
"hobby": "唱歌,跳舞,看电影,追剧"
}
}
]
}
}
2.2.3 修改数据
全量修改
POST:http://127.0.0.1:9200/user/_doc/1
request
{
"name":"托尼",
"age":22,
"hobby":"唱歌,跳舞,看电影,追剧"
}
response
{
"_index": "user",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}
version版本加1
局部修改
POST:http://localhost:9200/user/_update/1
request
{
"doc": {
"name":"派克"
}
}
response
{
"_index": "user",
"_type": "_doc",
"_id": "1",
"_version": 3,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 1
}
2.2.4 删除数据
DELETE:http://127.0.0.1:9200/user/_doc/1
2.3 条件查询
2.3.1 根据字段查询
GET:http://127.0.0.1:9200/user/_search
request
{
"query":{
"match":{
"name":"派克"
}
}
}
response
{
"took": 68,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.3862942,
"hits": [
{
"_index": "user",
"_type": "_doc",
"_id": "1",
"_score": 1.3862942,
"_source": {
"name": "派克",
"age": 22,
"hobby": "唱歌,跳舞,看电影,追剧"
}
}
]
}
}
2.3.2 分页查询
request
{
"query": {
"match_all": {}
},
"from": 1, // 从第几条查询
"size": 1, // 查询数量
"_source": [
"name",
"age"
], // 字段过滤,如果没有则查询所有字段
"sort": {
"age": "desc"
} // 按照年龄降序
}
response
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "user",
"_type": "_doc",
"_id": "1",
"_score": 1.0,
"_source": {
"name": "派克",
"age": 22
}
}
]
}
}
2.3.3 条件查询
查询姓名是汤姆或派克的用户
request
{
"query": {
"bool": {
"should": [
{
"match": {
"name": "汤姆"
}
},
{
"match": {
"name": "派克"
}
}
]
}
}
}
查询姓名是汤姆并且喜欢唱歌的用户
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "汤姆"
}
},
{
"match": {
"hobby": "唱歌"
}
}
]
}
}
}
2.3.4 范围查询
查询年龄超过21岁的用户
request
{
"query": {
"bool": {
"filter": {
"range": {
"age": {
"gt": 21
}
}
}
}
}
}
2.3.5 关键字精确查询
match匹配会根据查询参数进行分词,然后查询。如果不想对查询参数分词则需要使用match_phrase关键字
request
{
"query": {
"match_phrase": {
"name": "汤派"
}
}
}
这里不能查出数据。如果改为match,则会对汤派进行分词,查询出两条数据
2.3.6 高亮显示
对查询结果name字段高亮显示
request
{
"query": {
"match": {
"name": "汤"
}
},
"highlight": {
"fields": {
"name": {}
}
}
}
response
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.6931471,
"hits": [
{
"_index": "user",
"_type": "_doc",
"_id": "ABQIv3gB_sQQDSsOlaVw",
"_score": 0.6931471,
"_source": {
"name": "汤姆",
"age": 20,
"hobby": "唱歌,足球,篮球,爬山"
},
"highlight": {
"name": [
"<em>汤</em>姆"
]
}
}
]
}
}
2.3.7 聚合查询
根据年龄分组
request
{
"aggs": { // 聚合操作
"age_group": { // 名称,随意起名
"terms": { // 分组
"field": "age" // 分组字段
}
}
},
"size": 0 // 不要原始数据
}
response
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"age_group": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 22,
"doc_count": 2
},
{
"key": 20,
"doc_count": 1
},
{
"key": 21,
"doc_count": 1
}
]
}
}
}
求年龄平均值
request
{
"aggs": { // 操作
"age_avg": { // 名称,随意起名
"avg": { // 求平均值
"field": "age" // 统计字段
}
}
},
"size": 0 // 不要原始数据
}
response
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"age_avg": {
"value": 21.25
}
}
}
2.4 映射操作
2.4.1 创建映射
PUT:http://127.0.0.1:9200/student/_mapping
request
{
"properties": {
"name": {
"type": "text",
"index": true
},
"sex": {
"type": "text",
"index": false
},
"age": {
"type": "long",
"index": false
}
}
}
映射数据说明
字段名:任意填写,下面指定许多属性,例如:title、subtitle、images、price
type:类型,Elasticsearch中支持的数据类型非常丰富,说几个关键的
String类型,又分两种:
text:可分词
keyword:不可分词,数据会作为完整字段进行匹配
Numerical:数值类型,分两类
基本数据类型:long、integer、short、byte、double、float、half_float
浮点数的高精度类型:scaled_float
Date:日期类型
Array:数组类型
Object:对象
index:是否索引,默认为true,也就是说你不进行任何配置,所有字段都会被索引。
true:字段会被索引,则可以用来进行搜索
false:字段不会被索引,不能用来搜索
store:是否将数据进行独立存储,默认为false
原始的文本会存储在_source里面,默认情况下其他提取出来的字段都不是独立存储的,是从_source里面提取出来的。当然你也可以独立的存储某个字段,只要设置"store": true即可,获取独立存储的字段要比从_source中解析快得多,但是也会占用更多的空间,所以要根据实际业务需求来设置。
analyzer:分词器,这里的ik_max_word即使用ik分词器
2.4.2 查看映射
GET:http://127.0.0.1:9200/student/_mapping
response
{
"student": {
"mappings": {
"properties": {
"age": {
"type": "long",
"index": false
},
"name": {
"type": "text"
},
"sex": {
"type": "text",
"index": false
}
}
}
}
}
2.4.3 索引映射关联
PUT:http://127.0.0.1:9200/student
request
{
"settings": {},
"mappings": {
"properties": {
"name": {
"type": "text",
"index": true
},
"sex": {
"type": "text",
"index": false
},
"age": {
"type": "long",
"index": false
}
}
}
}