尚硅谷--雷丰阳--ElasticSearch 7.4.2版本
简介:
ElasticSearch是一个分布式,RESTful风格的搜索和数据分析引擎
官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
一、基本概念
1、index(索引)
动词:相当于MySql的insert
名词:相当于MySql的database
2、Type (类型)
在index中,可以定义一个或多个类型
类似于mysql的table,每种类型的数据放在一起
3、Document(文档)
保存在某个索引(index)下,某种类型(Type)的一个数据(Document),文档是json形式的,
Documnet类似于table中的一行
4、倒排索引机制
es会维持一个倒排索引,当其存入一个数据时,会对该数据中的内容进行分词,然后该词语后
维持一个该文档的id
二、ElasticSearch - Docker安装
1、下载镜像文件
docker pull elasticsearch:7.4.2
docker pull kibana:7.4.2
2、创建实例
创建文件夹和配置文件
mkdir -p /mydata/elasticsearch/config mkdir -p /mydata/elasticsearch/data echo "http.host : 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
创建容器
9200: restful请求的端口 9300:elasticsearch集群节点间通信端口 discovery.type=single-node 以单节点形式运行 ES_JAVA_OPTS 设置es运行的java虚拟机内存 -v :目录挂载 -d : 以守护进程方式运行
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \ -e "discovery.type=single-node" \ -e ES_JAVA_OPTS="-Xms64m -Xmx128m" \ -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.4.2
【注意】:启动错误时,需要改一下 数据目录的权限 /mydata/elasticsearch/data
chmod 777 /mydata/elasticsearch/data
访问 elasticsearch服务所在机器的 9200端口
http://192.168.25.129:9200/
3、【补充】 docker 安装kibana
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.25.129:9200 -p 5601:5601 \ -d kibana:7.4.2
访问kibana服务所在机器的5601端口
http://192.168.25.129:5601/
三、初步检索
1、_cat
GET /_cat/nodes : 查看所有结点
GET /_cat/health : 查看es的健康状况
GET /_cat/master : 查看主节点
GET /_cat/indices :查看所有索引
2、索引一个文档
保存一个数据,保存在哪个索引的哪个类型下,指定用哪个唯一标识
PUT customer/external/1 : 在customer索引下的 external 类型下保存1号数据
PUT customer/external/1 { "name":"houchen" }
返回数据:
{ "_index" : "customer", // 带_的为元数据 索引 "_type" : "external", "_id" : "1", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 0, "_primary_term" : 1 }
【总结】
PUT 和 POST都可以进行新增操作
PUT必须要带id,id存在的话即修改,id不存在的话则是新增
带id的情况下,多次PUT/POST是修改
不带id的情况下,多次POST是新增
3、查询文档
GET /customer/external/1
结果: { "_index" : "customer", //在哪个索引 "_type" : "external", //在哪个类型 "_id" : "1", //记录id "_version" : 1, //版本号 "_seq_no" : 0, //并发控制字段,每次更新就会+1,用来做乐观锁 "_primary_term" : 1, //同上,主分片重新分配,会重启就会变化 "found" : true, //是否找到 "_source" : { "name" : "houchen" } }
并发修改时,需要携带 _seq_no
4、更新文档
带 _update的更新语句:会对比原来的数据,如果没有变化,则版本号不会更新
POST customer/external/1/_update { "doc":{ "name":"john Doew" } }
不带_update的更新语句,会不断更新,叠加版本_version
POST customer/external/1 { "name":"john Doew" } PUT customer/external/1 { "name":"john Doew" }
5、删除文档和索引
删除文档
DELETE customer/external/1
删除索引
DELETE customer
6、bulk批量API
POST /customer/external/_bulk {"index":{"_id":"1"}} {"name":"111"} {"index":{"_id":"2"}} {"name":"222"}
复杂操作:
POST /_bulk {"delete":{"_index":"wehsite","_type":"blog","_id":"123"}} //删除文档 {"create":{"_index":"wehsite","_type":"blog","_id":"123"}} //创建文档 {"title":"My first blog post"} {"index":{"_index":"wehsite","_type":"blog"}} //索引文档 {"title":"My second blog post"} {"update":{"_index":"wehsite","_type":"blog","_id":"123"}} {"doc":{"title":"My second blog post"}}
【导入官网测试数据】
post /bank/account/_bulk { {"index":{"_id":"1"}} {"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"amberduke@pyrami.com","city":"Brogan","state":"IL"} {"index":{"_id":"6"}} {"account_number":6,"balance":5686,"firstname":"Hattie","lastname":"Bond","age":36,"gender":"M","address":"671 Bristol Street","employer":"Netagy","email":"hattiebond@netagy.com","city":"Dante","state":"TN"} {"index":{"_id":"13"}} }
https://download.elastic.co/demos/kibana/gettingstarted/accounts.zip
四、进阶检索
ES支持两种基本方式检索:
一个是通过使用 REST request URI来发送搜索参数(uri + 检索参数)
GET bank/_search?q=*&sort=account_number:asc
另一个是通过 REST request body 来发送他们 (uri + 请求体)
GET bank/_search { "query":{ "match_all":{} }, "sort":[ { "balance":{ "order":"desc" } } ], "from":0, "size":5, "_source":["balance","firstname"] }
1、match_all :查询所有
GET bank/_search { "query":{ "match_all":{} }, "sort":[ { "balance":"asc" } ] }
2、match查询
全文检索会按照评分进行排序,
首选需要对要查询的字符串进行分词,然后根据分词的结果进行匹配
最后根据得分进行排序
GET bank/_search { "query": { "match": { "address": "kings" } } }
3、match_phrase 【短语匹配】
将需要匹配的值,当成一个整体单词(不分词)进行检索
GET bank/_search { "query": { "match_phrase": { "address": "mill lane" } } }
4、multi_match 【多字段匹配】
也是分词查询
// 查询 adress或者city中包含 mill的数据 GET bank/_search { "query": { "multi_match": { "query": "mill", "fields": ["address","city"] } } }
5 bool查询
GET bank/_search { "query": { "bool": { "must":[ { "match": { "gender": "F" } }, { "match": { "address": "Mill" } } ] } } }
6、filter 结果过滤
只用于对数据进行过滤,不会计算相关性得分
GET bank/_search { "query": { "bool": { "filter": { "range": { "age": { "gte": 10, "lte": 20 } } } } } }
7、term 查询
和match一样。匹配某个属性的值。全文检索用match,其他非text字段匹配用term
GET /bank/_search { "query": { "term": { "balance": { "value": "32838" } } } }
精确匹配:查询address等于132 Gunnison的文档
GET bank/_search { "query": { "match": { "address.keyword": "132 Gunnison" } } }
8、aggregation (执行聚合)
聚合提供了从数据中分组和提取数据的能力。最简单的聚合大致等于SQL的聚合函数。
在ElasticSearch中,你有执行搜索返回hit,并且同时返回聚合结果,把一个响应中所有hits分隔开的
能力,这是非常强大且有效的。您可以执行查询和多个聚合并且在一次使用中得到各自的返回结果,使用一次简介和简化的api来避免网络往返
语法
"aggregations" : { "<aggregation_name>" : { //聚合名称 "<aggregation_type>" : { //聚合类型 <aggregation_body> //聚合体 } [,"meta" : { [<meta_data_body>] } ]? [,"aggregations" : { [<sub_aggregation>]+ } ]? } [,"<aggregation_name_2>" : { ... } ]* }
1)需求:搜索address中包含mail的所有人的年龄和平均年龄,但不显示这些人的详情
GET bank/_search { "query": { "match": { "address": "mill" } }, "aggs": { "ageagg": { "terms": { "field": "age", "size": 10 } }, "ageavg":{ "avg": { "field": "age" } }, "balanceavg":{ "avg": { "field": "balance" } } } }
2)按照年龄聚合,并求这些年龄段的人的平均薪资
(聚合里面套聚合)
GET /bank/_search { "query":{ "match_all": {} }, "aggs": { "ageAgg": { "terms": { "field": "age", "size": 10 }, "aggs": { "balanceAvg": { "avg": { "field": "balance" } } } } }, "size": 0 ##过滤掉查询的结果 }
3)查出所有的年龄分布,并且这些年龄段中M的平均薪资和F的平均薪资,以及这个年龄段总体的平均薪资
GET bank/_search { "query": { "match_all": {} }, "aggs": { "agegg": { //聚合年龄 "terms": { "field": "age", "size": 100 }, "aggs": { "genderagg":{ //在年龄的聚合结果上聚合性别 "terms": { "field": "gender.keyword", "size": 2 }, "aggs": { "balanceagg": { //xx岁 M性别的平均薪资 "avg": { "field": "balance" } } } }, "agebalanceaavg":{ //xx岁的平均薪资 "avg": { "field": "balance" } } } } } }
五、Mapping
1、ElasticSearch7去掉type的概念
关系数据库中两个数据表示是独立的,即使他们里面有相同名称的列也不影响使用,但ES中不是这样的。elasticsearch是基于Lucene开发的搜索引擎,而Es中不同type下名称相同的field最终咋Lucene中的处理方式是一样的
- 两个不同type下的user-name,在es同一个索引下其实被认为是同一个field,你必须在不同的
type中定义相同的field映射。否则,不同type中的相同字段名称就会在处理时出现冲突的情况,导致
Lucene处理效率下降
2、查看某个索引的映射
GET bank/_mapping
【注意】text属性的field,都会有一个keyword子属性
3、创建映射
PUT /my_index { "mappings":{ "properties": { "age":{"type":"integer"}, "name":{"type": "text"}, "email":{"type": "keyword"} } } }
4、添加新的映射字段
PUT /my_index/_mapping { "properties":{ "employ_id":{ "type":"keyword", "index":false //控制该字段能不能被检索 } } }
5、修改映射&
不能修改映射,因为这会导致已经存入的数据所拥有的索引规则不能用,只能新建一个索引和映射关系,并将旧的数据迁移过去
6、数据迁移
数据迁移:
POST _reindex { "source":{ "index":"bank" }, "dest":{ "index":"newbank" } }
如果是老版本的,包含type的
POST _reindex { "source":{ "index":"bank", "type":"account" }, "dest":{ "index":"newbank" } }
六、分词
1、简介
一个tokenizer(分词器)接收一个字符流,将之分隔为独立的tokens(词元,通常是独立的单词),然后输出tokens流
2、如何查看一句话的分词结果:
POST _analyze { "analyzer":"standard" //指定分词器:现在使用的是标准分词器 "text":"我爱北京天安门" }
不得不说啊:标准分词器真是low爆了:
3、安装ik分词器 (可以对中文进行分词)
ik分词器的github地址:
https://github.com/medcl/elasticsearch-analysis-ik
我的es是 7.4.2版本
1)由于elasticsearch容器启动时,指定了文件挂载:-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins
所以,只需要将ik分词器下载到 /mydata/elasticsearch/plugins,并进行解压
2)进入elasticsearch容器内部
docker exec -it fe25cc93c122 /bin/bash
3)使用ik分词器,查看分词结果
4、自定义扩展词库
网络上的流行新词,ik分词器则不支持,此时就需要扩展词库
七、ElasticSearch-Rest-Client
1、ElasticSearch Client
1)、9300:TCP
spring-data-elasticsearch:transport-api.jar
springboot版本不同,transport-api.jar不同。不能适配es版本
7.x已经不建议使用,8以后就要废弃
2)、9200:HTTP
JestClient:非官方更新慢
RestTemplate: 模拟发送HTTP请求,ES的很多操作需要自己封装,麻烦
HttpClient: 同上
Elasticsearch-Rest-Client:官方的RestClient,封装了ES操作,API层次分明,上手简单
最终选择 lasticsearch-Rest-Client(elasticsearch-rest-high-level-client)
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html
2、保存
@RunWith(SpringRunner.class) @SpringBootTest class EsApplicationTests { @Autowired private RestHighLevelClient client; /** * 测试存储数据到es * 更新也可以 */ @Test void indexData() throws IOException { IndexRequest indexRequest = new IndexRequest("users"); indexRequest.id("1"); User user = new User("zhangsan", "男", 18); String jsonString = JSON.toJSONString(user); indexRequest.source(jsonString, XContentType.JSON); //执行操作 IndexResponse index = client.index(indexRequest, ElasticSearchConfig.COMMON_OPTIONS); //提取有用的操作数据 System.out.println(index); } @Data static class User{ private String userName; private String gender; private Integer age; public User(String userName, String gender, Integer age) { this.userName = userName; this.gender = gender; this.age = age; } } }