目录结构
1、简介
1、为什么要使用ElasticSearch
Mysql: 使用mysql进行单表的计算(平均值等),如果数据达百万级别以上,则查询速度太慢
ElasticSearch: 查询速度快,在整站中进行检索
2、如何调用
ElasticSearch底层是开源库Lucene。对Lucene进行封装,提供REST API接口,直接调用相关api即可完成相应的检索操作
2、基本概念
1、Index(索引)
动词, 相当于MySQL的insert(保存一条数据到ElasticSearch中: 索引一条数据)
名词, 相当于MySQL的Database
2、Type(类型)
在一个Index(索引)中可以定义一个或多个类型(类似于mysql中的表);
通过type,将每一种类型的数据归类在一起
3、Document(文档)
ElasticSearch存储的数据
保存在某个索引(index)下,某种类型(type)的一个数据(document),文档是JSON格式
4、Attribute(属性)
5、倒排索引(查询速度快的原因)
ES中会自动维护一张倒排索引表:
- 经历步骤
- 分词: 将一句话拆分成一个个单词,记录单词与数据的关系
- 检索: (1)将检索条件分词 (2)查询倒排记录表、匹配每一个单词 (3)获得匹配记录的结果
- 相关性得分: 获得多条匹配结果后,会根据符合结果的条件,获得相关性评分,并且将记录按照相关性得分从高到低排序
2、ElasticSearch安装(docker)
1、下载镜像
docker pull elasticsearch:7.4.2 #存储和检索数据
docker pull kibana:7.4.2 #可视化检索数据
2、创建实例
创建外部主机文件夹,实现对doker容器内的es目录进行挂载
挂载完成后,可以直接通过对虚拟机的目录下文件的修改直接影响到docker容器内的配置文件
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data
创建配置文件,表示es允许任何的远程的主机访问
echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
启动es实例
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 --privileged=true \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-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
- docker run 参数解释
- name: 为运行的创建实例创建名称
- p: 暴露端口
- XXX:xxx: XXX:当前主机的的端口 xxx:映射到实例的端口
- e: 指定运行参数
- discovery.type: 以什么方式运行(single-node:单节点)
- ES_JAVA_OPTS: 执行时实例所占用的内容(-Xms64m, -Xmx128m) 最小占用、最大占用
- v: 挂载到什么目录
- d: 运行的镜象
运行报错,因为挂载到的文件的权限有问题(只允许root用户可读可写),修改文件夹权限
# 给文件夹授权(7:超级管理员 7:创建者 7:一般用户)
chmod -R 777 /mydata/elasticsearch/
3、Kibana安装(docker):可视化操作elasticsearch
docker run --name kibana \
-e ELASTICSEARCH_HOSTS='本级的elasticsearch暴露的ip端口及地址(例如:http://192.168.125.129:9200)' -p 5601:5601 \
-d kibana:7.4.2
4、初步检索
1、_cat
GET /_cat/nodes: 查看所有节点
GET /_cat/health: 查看es健康状况
GET /_cat/master: 查看主节点
GET /_cat/indices: 查看所有索引 <==>等价与 mysql show databases
2、索引一个文档(保存)
保存一个数据,保存在哪个索引的哪个类型下,指定用哪个唯一标识
// 在customer索引下的external类型下保存1号数据为
请求: PUT {indexName}/{typeName}/{id};
保存的数据(JSON):
{
"name":"John Doe"
}
PUT请求(必须携带id):
POST请求(携带id更新、不携带id保存):
- 注意
PUT 和 POST请求都可以
POST新增。如果不指定id,会自动生成id。指定id就会修改这个数据,并新增版本好
PUT可以新增可以修改。PUT必须指定id;由于PUT需要指定id;我们一般都用来做修改操作,不指定id会报错
3、查询文档
请求
// 发送请求
GET {indexName}/{typeName}/{id }
更新时携带相应的乐观锁字段 *? if_seq_no = 0&&if_primary_term=1 *
4、更新文档
方法一: _update
会对比元数据、如果对比相同、则不修改(版本号 version\序列号seq_no)
同时更新的时候也可以增加属性
// 发送请求
POST {indexName}/{typeName}/{id}/_update
// 请求体
{
"doc":{
// 修改相应的JSON数据
"name": "John Doew",
// 增加相应的属性
"age": 20
}
}
方法二:
// 发送请求
POST {indexName}/{typeName}/{id}
// 请求体
{
// 相应的JSON数据
"name": "John Doew",
// 增加相应的属性
"age": 20
}
方法三:
// 发送请求
PUT {indexName}/{typeName}/{id}
// 请求体
{
// 相应的JSON数据
"name": "John Doew",
// 增加相应的属性
"age": 20
}
5、删除文档&索引
// 删除文档
DELETE {indexName}/{typeName}/{id}
// 删除索引
DELETE customer
6、bluk批量api
POST {indexName}/{typeName}/_bulk
{action: {metadata}}
{request body}
{action: {metadata}}
{request body}
4、进阶检索
1、SearchAPI
ES支持两种基本方式检索:
- 一个是通过使用 REST request URI 发送搜索参数(uri+检索参数)
- 另一个是通过使用 REST request body 来发送它们(uri+请求体)
1) 检索信息
- 一切检索从_search开始
请求体里面设置搜索条件
GET /bank/_search
// 请求体
{
"query": {
"match_all": { }
},
"sort": [
{
"account_number": "desc"
}
]
}
2、Query DSL
1)、基本语法格式
领域对象语言
基本样式
// 查询所有
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,.....
}
// 针对某一字段查询
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,.....
}
}
}
2)、典型例子
例如
GET /bank/_search
{
// 匹配字段
"query": {
"match_all": { }
},
// 排序
"sort": [
{
"balance": {
"order": "desc"
}
}
],
// 从哪个索引位置开始
"from": 0,
// 查询的条数
"size": 20,
// 指定返回数据字段(account_number, balance, firstname)
"_source": ["account_number","balance","firstname"]
}
返回结果
3)、match[匹配查询]
全文检索: 最终会按照评分排序,会对检索条件进行分词匹配
- 基本类型(非字符串),精确匹配
例如:
- 字符串查询(模糊匹配):
4)、match_phrase[短语匹配]
将需要匹配的值当成一个整体单词(不分词)进行检索: 将整个短语进行匹配
GET /bank/_search
{
"query": {
"match_phrase": {
"address": "mill lane"
}
}
}
或者是使用keyword 进行精确匹配
GET /bank/_search
{
"query": {
"match": {
"address.keyword": "789 Madison Street"
}
}
}
区别
match_phrase 匹配短语是进行的模糊匹配
keyword关键字是进行的精确匹配
例如:
5)、multi_match[多字段匹配]
查出多个字段 中符合条件值的 文档
GET /bank/_search
{
"query": {
"multi_match": {
"query": "mill",
"fields": ["address","city"]
}
}
}
6)、bool[复合查询]
bool用来做复合查询:
复合语句可以合并 任何 其他查询语句,包括复合语句。这就意味着,复合语句之间可以互相嵌套,可以表达非常复杂的逻辑
-
must: 必须达到must列举的所有条件
-
must_not: 必须不满足列举的条件
-
should: 可以满足可以不满足(满足得分更高)
7)、filter[结果过滤]
filter: 不会影响相关性得分,
用于对获得的最终结果进行过滤
8)、term[与match类似: 如果是精确匹配(数值),则推荐用term]
全文检索字段用match
其他非text字段匹配用term
3、Aggregations(聚合)
1)、aggregations[执行聚合]
聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致等于SQL GROUP BY和SQL聚合函数。在Elasticsearch中,您有执行搜索返回hits (命中结果),并且同时返回聚合结果,把一个响应中的所有hits (命中结果)分隔开的能力。这是非常强大且有效的,您可以执行查询和多个聚合,并且在一次使用中得到各自的(任何一个的)返回结果,使用一次简洁和简化的API来避免网络往返。
搜索address中包含mill的所有人的年龄分布以及平均年龄,但不显示这些人的详情
GET /bank/_search
{
"query": {
"match": {
"address": "mill"
}
},
"aggs": {
"ageAgg": {
"terms": {
"field": "age",
"size": 10
}
},
"ageAvg": {
"avg": {
"field": "age"
}
},
"balanceAvg": {
"avg": {
"field": "balance"
}
}
},
"size": 0
}
按照年龄聚合,并且请求这些年龄段的这些人的平均薪资
GET /bank/_search
{
"query": {
"match_all": {}
},
"aggs": {
"ageAgg": {
"terms": {
"field": "age",
"size": 100
},
"aggs": {
"balanceAgg": {
"avg": {
"field": "balance"
}
}
}
}
}
}
查出所有年龄分布,并且在这些年龄段中M的平均薪资和F的平均薪资以及这个年龄段的总体平均薪资
GET /bank/_search
{
"query": {
"match_all": {}
},
"size": 0,
"aggs": {
"ageAgg": {
"terms": {
"field": "age",
"size": 100
},
"aggs": {
"genderAggs": {
"terms": {
"field": "gender.keyword"
}
, "aggs": {
"balanceAgg": {
"avg": {
"field": "balance"
}
}
}
},
"ageBalanceAggs": {
"avg": {
"field": "balance"
}
}
}
}
}
}
3、Mapping(映射)
ES会在第一次保存数据的时候,自动猜测数据是何种类型,完成相应的类型匹配
1) 字段类型:
ES6.0移除了类型的概念
原因:
(1) 查看mapping信息
GET bank/_mapping
(2) 创建索引并指定映射(已不建议使用)
PUT /my_index
{
"mappings": {
"properties": {
"age": {"type": "integer"},
"email": {"type": "keyword"},
"name": {"type": "text"}
}
}
}
(3) 给已存在的index, 添加新的字段映射
PUT /my_index/_mapping
{
"properties": {
"employee-id": {
"type": "keyword",
"index": false // index不需要被索引,永远都不会参与检索
}
}
}
(4)更新映射(数据迁移)
- 1、创建新的索引、指定正确的映射关系
- 2、将创建好的索引数据迁移到原来的索引当中
创建新的索引
数据迁移
新版本 6.0之后
POST _reindex //[当创建的索引不存在类型时 6.0之后]
{
"source": {
"index" : "blank"
},
"dest": {
"index": "new_blank"
}
}
存在type类型:
5、分词
1)安装ik分词器
github地址:
https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.4.2
因为上一步已经将plugin挂载到虚拟机本机的文件夹内,则对文件夹操作即可操作容器内部的文件
做好挂载后:
按步骤安装即可
安装完成后进入容器内容即可查看分词器是否安装完成
重启docker elasticsearch服务
POST _analyze
{
"analyzer": "ik_smart",
"text": "尚硅谷电商项目"
}
2)自定义扩展词库
修改ik分词器的配置文件、即可进行自定义扩展
步骤:
1、安装nginx
#安装
docker run -p 80:80 --name nginx \
-v /mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx \
-v /mydata/nginx/conf:/etc/nginx \
-d nginx:1.10
2、配置自定义扩展字典
输入想要添加的分词
补充
新建索引: nested类型
// 如果在es存储的关键字为对象数组,如果不加nested类型,则会展示的对象数组会被扁平化处理
// 例如执行此命令
PUT my_index/my_type/1
{
"group" : "fans",
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
}
// 实际在elasticsearch存储的为
{
"group" : "fans",
"user.first" : [ "alice", "john" ],
"user.last" : [ "smith", "white" ]
}