0. 基本概念
Elasticsearch在数据分析和处理方面强于Mysql,Mysql主要是数据的持久化结构化存储,而在海量数据检索方面Elasticsearch更强。 Es是对Lucene的封装,直接提供Rest Api。
- Index 索引 动词:Insert/名词:Database
- Type 类型 在Index中,可以定义一个或多个类型,相当于DataBase中的Table。
- Document 文档 相当于表中的一条记录
1. Es为什么快? -- 倒排索引
倒排索引:存储数据的时候,先把数据拆分为单词,即“分词”,在倒排索引表中,维护着每个单词所在的记录。在检索关键词的时候就会快速得到包含该关键词的记录,即“文档”。
相关性得分:检索出的所有文档,会根据相关性得分,最终返回检索结果。举一个教程中的例子:
倒排索引表:
| 单词 | 记录 |
|---|---|
| 红海 | 1,2,3,4,5 |
| 行动 | 1,2,3 |
| 探索 | 2,5 |
| 特别 | 3,5 |
| 记录篇 | 4 |
| 特工 | 5 |
保存的记录:
1 - 红海行动 2 - 探索红海行动 3 - 红海特别行动 4 - 红海记录篇 5 - 特工红海特别探索
比如检索“红海特工行动”,红海- 特工-行动,三个单词,在倒排索引表中可以看到记录12345记录中都存在,所以第一步是查询到所有的5条记录,或者说5个文档,其中1号记录两个单词全部命中,2、3号记录3个单词命中两个,4号记录两个单词命中1个,5号记录4个单词命中两个,所以相关性得分1号记录胜出,即为最终的结果。
2. docker 安装 es 和 kibana
安装:参考之前的文章,镜像版本号可以自行指定:juejin.cn/post/684490…
这里按照步骤安装:
- 创建数据卷
sudo mkdir -p /home/chins/docker/elasticsearch/volume/config
sudo mkdir -p /home/chins/docker/elasticsearch/volume/data
- 写入配置,允许任意主机访问(权限不够就切换成root用户)
# 注意这里是k-v之间有空格
sudo echo "http.host: 0.0.0.0" >> /home/ubuntu/volumes/elasticsearch/config/elasticsearch.yml
- 启动es容器
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -v /home/chins/docker/elasticsearch/volume/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /home/chins/docker/elasticsearch/volume/data:/usr/share/elasticsearch/data -v /home/chins/docker/elasticsearch/volume/plugins:/usr/share/elasticsearch/plugins -d elasticsearch:7.4.2
如果启动不成功,docker logs查看发现下图,是因为其他用户组的权限不足,这里直接改成777。
chmod -R 777 /elasticsearch/volume/
- 启动kibana容器
# elasticsearch容器的ip
docker inspect 03b7f9574290 | grep ip
docker run -d --name kibana -e ELASTICSEARCH_HOSTS=http://172.17.0.3:9200 -p 5601:5601 -d kibana:7.4.2
3. es基本操作
| 命令 | 解释 |
|---|---|
| GET _cat/nodes | 查询所有节点 |
| GET _cat/health | 查看es集群健康状况 |
| GET _cat/master | 查看主节点 |
| GET _cat/indices | 查看所有索引 (show databases) |
3.1 索引一个文档 -- 保存一条记录 put和post都可以
## 索引(数据库):customer,类型(表名):external,编号为1
PUT customer/external/1
{
"name": "Bob"
}
3.2 查询文档
## 索引/类型/id
GET customer/external/1
响应中有一个_seq_no字段,作用是乐观锁,并发控制,每次更新都会加1
PUT customer/external/1?if_seq_no=1&if_primary_term=1,两个人都想修改id为1的,当其中一个修改成功,_seq_no就会加1,此时另一个就不会修改成功了。
3.3 更新文档
## 会和原来的数据对比,如果一样,那么就不会改变,包括版本号、seq_no等都不会变
POST customer/external/1/_update
{
"doc": {
"name": "Andy"
}
}
或者
## 每次都会更新数据,版本号等都会更新
POST/PUT customer/external/1
{
"name":"Andy"
}
3.4 删除文档&索引(没有删除类型)
DELETE customer/external/1
DELETE customer
3.5 批量API
POST customer/external/_bulk
## 两行是一组
{"index": {"_id": 1}}
{"name": "David"}
{"index": {"_id": 2}}
{"name": "Jane"}
3.6 检索
GET bank/_search?q=*&sort=account_number:asc
或:
GET bank/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"account_number": "asc"
},
{
"balance": "desc"
}
],
"from": 0,
"size": 5,
"_source": ["字段1", "字段2"]
}
请求体就叫做queryDSL(领域对象语言)
3.6.1 match
{
"query": {
"match": {
"account_number": 20
}
}
}
match去检索一个非字符串,那么相当于精确匹配,如果是字符串,相当于模糊查询。
{
"query": {
"match": {
"address": "Kings"
}
}
}
在结果中会有_score,描述结果的分词匹配程度。
3.6.2 match_phrase
不对检索条件进行分词(区别于match,match会分词)
3.6.3 multi_match 多字段匹配
{
"query": {
"multi_match": {
"query": "mill",
"fields": ["address", "city"]
}
}
}
## address\city字段包含mill,都会匹配到
4. bool 查询 - 合并多个查询
{
"query": {
"bool": {
"must": [
{
"match": {
"gender": "F"
}
},
{
"match": {
"address": "mill"
}
}
],
"must_not": [
{
"match": {
"age": "38"
}
}
],
"should": [ ## 可以满足,不满足也没关系,影响的是_score
{
"match": {
"lastname": "Wallace"
}
}
]
}
}
}
4.1 filter过滤
filter和must should一样,但是不影响相关性得分。
5. term查询
term和match一样,精确到字段比如年龄等,用term查询,其他的字符串等需要全文检索的,用match查询
6. 聚合查询 aggregations
类比于Group By、sql的聚合函数等。比如搜索address中包含mill的所有人的年龄分布以及平均年龄,但是不需要这些人的详情:
GET bank/_search
{
"query": {
"match": {
"address": "mill"
}
},
"aggs": {
"ageAgg": {
"terms": {
"field": "age",
"size": 10 // group by age
}
},
"aggAvg": {
"avg": {
"field": "age" // avg(age)
}
}
}
}