es是什么
The Elastic Stack, 包括 Elasticsearch、Kibana、Beats 和 Logstash(也称为 ELK Stack)。 能够安全可靠地获取任何来源、任何格式的数据,然后实时地对数据进行搜索、分析和可视化。Elaticsearch,简称为 ES,
ES 是一个开源的高扩展的分布式全文搜索引擎,是整个 Elastic Stack 技术栈的核心。它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上 百台服务器,处理 PB 级别的数据。
为什么会有es
mysql缺点
因为mysql如果无法命中任何索引,会触发全表扫描。 而且数据量大的话,分库分表维护麻烦。
es优点
轻松支持各种复杂的查询条件
会把每一个字段都编入索引(倒排索引),利用高效的倒排索引,以及自定义打分、排序能力与丰富的分词插件等,能实现任意复杂查询条件下的全文检索需求
可扩展性强--天然支持分布式存储
高可用,容灾性能好
据说,clickhouse和doris 以后可能会替代mysql
es 的安装
docker安装
(1)下载
docker pull elasticsearch:7.7.0
docker pull kibana:7.7.0
(2)配置
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data
echo "http.host: 0.0.0.0" /mydata/elasticsearch/config/elasticsearch.yml
chmod -R 777 /mydata/elasticsearch/
(3)启动Elastic search
docker run --name elasticsearch -d -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.7.0
设置开机启动elasticsearch
docker update elasticsearch --restart=always
(4) 启动kibana
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.10.102:9200 -p 5601:5601 -d kibana:7.7.0
设置开机启动kibana
docker update kibana --restart=always
(5)测试
查看elasticsearch版本信息: <http://yourip:9200/>
{
"name": "0adeb7852e00",
"cluster_name": "elasticsearch",
"cluster_uuid": "9gglpP0HTfyOTRAaSe2rIg",
"version": {
"number": "7.6.2",
"build_flavor": "default",
"build_type": "docker",
"build_hash": "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date": "2020-03-26T06:34:37.794943Z",
"build_snapshot": false,
"lucene_version": "8.4.0",
"minimum_wire_compatibility_version": "6.8.0",
"minimum_index_compatibility_version": "6.0.0-beta1"
},
"tagline": "You Know, for Search"
}
这样式儿的就ok。
es的基本概念
Index (索引) ----相当于mysql的 库
Type (类型) ----相当于mysql的表
document (文档) ----相当于表中的数据
es的基本测试
postman的使用
使用postman来对es发送请求,因为从网站上只能发送get请求,而postman,则都可以。
接下来我们就使用postman来对es做一些基本的测试和使用。
_cat---查看基本信息
首先查看状态
192.168.10.102:9200/_cat/health
查看主节点
192.168.10.102:9200/_cat/master
主节点就是我们生成的那个
接下来,查看索引---相当于 showdatabases
192.168.10.102:9200/_cat/indices
索引一个文档————————mysql(保存)
保存一个数据,要知道保存到那个索引的那个类型下,指定使用那个标识。 可以用put和post来保存
首先用put带id的来保存
192.168.10.102:9200/customer/external/1
如果再次发送,他就会变成一个更新操作。版本号会发生变化。
接下来用post不带id的来保存。
如果加了id,他还是一个更新操作
不加id,他就会随即生成一个。
那put如果不带id呢?
会报错。
小总结
put只能带id的保存。post既可以带id保存,也可以不带id保存。
查询
查询发送get请求就可以
192.168.10.102:9200/customer/external/1
每个字段代表的意思
"_index" : "customer",//在哪个索引
"_type" : "external", //在哪个类型
"_id": "1", //记录id
"_version": 2, //版本号
"_seq_no" : 1, //并发控制字像,每次更新就会+1,用来做乐观锁
" _primary_term": 1, //同上,主分片重新分配,如重启,就会变化"found": true,
"_source": {
//真正的内容
"name" : "lao bai"
}
_primary_term用来做更新操作的时候,可以在后面加上参数。 比如
192.168.10.102:9200/customer/external/1?if_seq_no=17&if_primary_term=1
通过“if_seq_no=16&if_primary_term=1 ”,当序列号匹配的时候,才进行修改,否则不修改
这个是发送成功的。
如果再次发送请求就会报错
更新文档
(1)POST更新文档,带有_update
post更新的操作就是在后面添加一个/_update
带update的时候,记得把他的数据都写到doc里面
192.168.10.102:9200/customer/external/1/_update
如果再次点击发送请求,他的状态会显示noop,表示没有更新成功,并且版本号不会发生变化。
(2)POST更新文档,不带_update
在更新过程中,重复执行更新操作,数据也能够更新成功,不会和原来的数据进行对比。
删除索引/文档
删除文档
delete请求
192.168.10.102:9200/customer/external/1
再次点击send
会发现result里面会报notfound
删除索引
直接把索引放上去就ok
192.168.10.102:9200/customer
bulk批量处理
POST customer/external/_bulk
"index":{"_id":"1""}
{"name": "John Doe" } //两个为一组
"index":{"_id":"2"
"{"name": "Jane Doe"}
语法格式:
{ action: { metadata lln{request body]\n
{ action: { metadata ln{request body}\n
复杂实例:
POST /_bulk
{ "delete" : { "_index": "website" , "_type": "blog"."_id": "123" l
{"create": { "_index" : "website" , "_type": ""blog","_id": "123" "}}
{"title"": "My first blog post" }
{ "index": { "_index" : "website", " _type": "blog" }}
接下来,我们做个测试
POST customer/external/_bulk
{"index":{"_id":"1"}}
{"name":"John Doe"}
{"index":{"_id":"2"}}
{"name":"John Doe"}
每条操作都是独立的,也就说,上面的操作不会影响到下一条的执行。
在测一个复杂的
POST /_bulk
{"delete":{"_index":"website","_type":"blog","_id":"123"}}
{"create":{"_index":"website","_type":"blog","_id":"123"}}
{"title":"my first blog post"}
{"index":{"_index":"website","_type":"blog"}}
{"title":"my second blog post"}
{"update":{"_index":"website","_type":"blog","_id":"123"}}
{"doc":{"title":"my updated blog post"}}
返回的结果
#! Deprecation: [types removal] Specifying types in bulk requests is deprecated.
{
"took" : 231, //消耗的时间
"errors" : false, //是否错误
"items" : [
{
"delete" : {
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"result" : "not_found", //返回结果,我们没有个这个类型
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 404
}
},
{
"create" : {
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 2,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1,
"status" : 201
}
},
{
"index" : {
"_index" : "website",
"_type" : "blog",
"_id" : "j9s8OYIBhvx6bCrS0D2N",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1,
"status" : 201
}
},
{
"update" : {
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 3,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 3,
"_primary_term" : 1,
"status" : 200
}
}
]
}
发现没有问题。
接下来,我们引入数据来测试。下面这个是测试地址。
elasticsearch/accounts.json at v7.4.2 · elastic/elasticsearch (github.com)
POST bank/account/_bulk.
后面加上我们的测试数据
es进阶
检索
ES支持两种基本方式检索;
- 通过REST request uri 发送搜索参数 (uri +检索参数);
- 通过REST request body 来发送它们(uri+请求体);
信息检索
一切检索从_search开始
GET bank/_search //检索bank下所有信息,包括type和docs
GET bank/_search?q=*&sort=account_number:asc //请求参数方式检索
响应结果解释:
took -Elasticsearch 执行搜索的时间(毫秒)
time_out- 告诉我们搜索是否超时
_shards- 告诉我们多少个分片被搜索了,以及统计了成功/失败的搜索分片
hits- 搜索结果
hits.total- 搜索结果
hits.hits- 实际的搜索结果数组(默认为前10的文档)sort-结果的排序key(键)(没有则按score排序)
score和 max_score -相关性得分和最高得分(全文检索用)
第一种实例
GET bank/ _search?q=*&sort=account_number:asc
第二种实例 QueryDSL
GET bank/_search
{
"query": {
"match_all": {} //找* ,也可以使用 _source:["field","field"],里面填参数,找具体的内容
},
"sort": [ //表示用什么字段排序
{
"balance": {
"order": "desc"
}
}
],
"from": 0, //从哪开始
"size": 50 //找多少数据
}
全文检索
GET bank/_search
{
"query": {
"match": {
"address": "mill lone"
}
}
}
全文检索会按照评分排序来返回结果
这样式儿的 这样评分都差不多
有个短语匹配,他会匹配短语里面所有的词儿。
短语匹配&字段匹配
GET bank/_search
{
"query": {
"match_phrase": {
"address": "mill road"
}
}
}
短语匹配是只要有,他就可以匹配到。
而match的字段匹配则是要精准
文本字段的匹配,使用keyword,匹配的条件就是要显示字段的全部值,要进行精确匹配的。
match_phrase是做短语匹配,只要文本中包含匹配条件,就能匹配到。
多字段匹配
state或者address中包含mill,并且在查询过程中,会对于查询条件进行分词。
GET bank/_search
{
"query": {
"multi_match": {
"query": "mill",
"fields": [
"state",
"address"
]
}
}
}
bool复核查询
复合语句可以合并,任何其他查询语句,包括符合语句。这也就意味着,复合语句之间 可以互相嵌套,可以表达非常复杂的逻辑。
must:必须达到must所列举的所有条件
must_not,必须不匹配must_not所列举的所有条件。
should,应该满足should所列举的条件。满足的话加的分更多。
GET bank/_search
{
"query":{
"bool":{
"must":[ //must里面包含查询条件match/match_all/match_phrase
{"match":{"address":"mill"}},
{"match":{"gender":"M"}}
]
}
}
}
filter
并不是所有的查询都需要产生分数,特别是哪些仅用于filtering过滤的文档。为了不计算分数,elasticsearch会自动检查场景并且优化查询的执行。
GET bank/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"address": "mill"
}
}
],
"filter": {
"range": {
"balance": {
"gte": "10000",
"lte": "20000"
}
}
}
}
}
}
这里先是查询所有匹配address=mill的文档,然后再根据10000<=balance<=20000进行过滤查询结果
没有添加之前是4个
添加完之后是1个
term
match在匹配时会对所查找的关键词进行分词,然后按分词匹配查找,而term会直接对关键词进行查找。一般模糊查找的时候,多用match,而精确查找时可以使用term。 ( 参考)
聚合
聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致等于SQL Group by和SQL聚合函数。在elasticsearch中,执行搜索返回this(命中结果),并且同时返回聚合结果,把以响应中的所有hits(命中结果)分隔开的能力。这是非常强大且有效的,你可以执行查询和多个聚合,并且在一次使用中得到各自的(任何一个的)返回结果,使用一次简洁和简化的API啦避免网络往返。
"aggs":{
"aggs_name这次聚合的名字,方便展示在结果集中":{
"AGG_TYPE聚合的类型(avg,term,terms)":{}
}
},
按照年龄聚合,并且求这些年龄段的这些人的平均薪资
GET bank/_search
{
"query": {
"match_all": {}
},
"aggs": {
"ageAgg": {
"terms": {
"field": "age",
"size": 100
},
"aggs": {
"ageAvg": {
"avg": {
"field": "balance"
}
}
}
}
},
"size": 0
}
映射
在ES中映射类似关系型数据库中的schema,描述了文档中有哪些字段和字段的类型,如string,data,int等。而 类型 是一组具有相关性的映射组成,然后使用"properties"来表示该类型中可能包含的字段属性。
部分如下
{
"bank" : {
"mappings" : {
"properties" : {
"account_number" : {
"type" : "long"
},
"address" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"age" : {
"type" : "long"
},
"balance" : {
"type" : "long"
},
"city" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"email" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
具体的参考