1 docker安装ElasticSearch
# 下载镜像
docker pull elasticsearch:5.6.8
# 创建并启动容器
docker run -di --name=docker_elasticsearch -p 9200:9200 -p 9300:9300 elasticsearch:5.6.8
因云服务器内存太小,无法启动docker上的elastic,此处将不再进行下去
2 windows安装ElasticSearch
-
解压安装包如下
elasticSearch-windows.png config目录下有
elasticsearch.yml
配置文件,可在里面修改配置,其基本配置如下
# 集群名称
cluster.name: my-application
# 当前节点名称
node.name: node-1
# 数据存放路径,默认是在ES安装目录下的data
#path.data: /path/to/data
# 日志存放路径,默认是在ES安装目录下的logs
#path.logs: /path/to/logs
# 绑定地址 默认是本机 localhost ,如果需要允许其他机器访问,可以设置为本机IP或者 0.0.0.0
#network.host: 192.168.0.1
# ES的HTTP连接地址,默认9200
#http.port: 9200
- 修改完成后,可双击
bin
目录下的elasticsearch.bat
启动 - 访问
本机:9200
看到以下页面即启动成功
elasticSerach首次启动后访问.png
3 安装ik分词器
-
elasticSearch/plugin
文件夹下创建ik
文件夹 - 解压
elasticsearch-analysis-ik-6.2.4.zip
- 将解压包下
elasticsearch
内所有文件复制到elasticSearch/plugin/ik
下 - 重启
elasticsearch
4 安装kibana
-
解压安装包
kibana.png - 修改配置文件
config/kibana.yml
# Web界面访问地址
#server.port: 5601
# 配置ES地址
#elasticsearch.url: "http://localhost:9200"
- 双击
bin/kibana.bat
启动 - 访问
http://127.0.0.1:5601/
kibana首页.png - kibana测试
在kibana左侧做到Dev Tools,输入请求命令,效果如下
POST _analyze
{
"analyzer": "ik_max_word",
"text": "我是中国人"
}
5 操作索引库
5.1 elastic概念
elasticSearch对比mysql
索引库(indices)---------------------------------Database 数据库
类型(type)----------------------------------Table 数据表
文档(Document)---------------------------------Row 行
字段(Field)--------------------------------Columns 列
映射配置(mappings)-------------------------------每个列的约束(类型、长度)
详细说明:
概念 | 说明 |
---|---|
索引库 (indices) | indices是index的复数,代表许多的索引 |
类型(type) | 类型是模拟mysql中的table概念,一个索引库下可以有不同类型的索引,类似 数据库中的表概念。数据库表中有表结构,也就是表中每个字段的约束信息; 索引库的类型中对应表结构的叫做 映射(mapping) ,用来定义每个字段的约 束。 |
文档 (document) | 存入索引库原始的数据。比如每一条商品信息,就是一个文档 |
字段(field) | 文档中的属性 |
映射配置 (mappings) | 字段的数据类型、属性、是否索引、是否存储等特性 |
5.2 操作索引库
- 创建索引库,可指定参数,也可不指定,7之前默认5个分片
# 创建
PUT itheima1
{
"settings": {
"number_of_shards": 5
}
}
- 查看索引库
GET 索引库名
GET itheima1
- 删除索引库
DELETE 索引库名
DELETE itheima1
5.3 操作类型及映射
- 创建映射关系
语法
PUT 索引库名/_mapping/类型名称
{
"properties": {
"字段名": {
"type": "类型",
"index": true,
"store": true,
"analyzer": "分词器"
}
}
}
类型名称:就是前面将的type的概念,类似于数据库中的表 字段名:任意填写,
在ES5.X版本中一个索引库中可以添加多个类型,相当于一个数据库添加多个表
在ES6.X版本中就不能通过REST请求在一个索引库中添加多个类型,但是从ES5.X升级到ES6.X的多个类型依旧可用
但是在ES7版本后,一个索引库只能有一个类型,为了兼容ES7,这里的类型最好设置为_doc
下面指定许多属性,例如:
- type:类型,可以是text、long、short、date、integer、object等
- index:是否索引,默认为true
- store:是否存储,默认为false
- analyzer:分词器,这里的 ik_max_word 即使用ik分词器
eg:
PUT itheima/_mapping/_doc
{
"properties": {
"title":{
"type": "text",
"analyzer": "ik_max_word"
},
"images":{
"type": "keyword",
"index": false
},
"price":{
"type": "float"
}
}
}
- 查看映射关系
# 查看索引库中所有映射关系
GET /索引库名/_mapping
# 查看索引库中指定映射关系
GET /索引库名/_mapping/映射名
5.4 创建索引库和类型
put 索引库名
{
"settings": {
"索引库属性名": "索引库属性值"
},
"mappings": {
"类型名": {
"properties": {
"字段名": {
"映射属性名": "映射属性值"
}
}
}
}
}
5.5 操作文档
- 新增文档:向索引库中类型下新增数据,类比数据库下的一行数据
POST /索引库名/类型名
{
"key": "value"
}
- 查看文档
GET 索引库/类型/文档编码
- 新增文档并指定id
POST /索引库名/类型名/自己指定id
{
"key": "value"
}
- 更新文档(若原类型中有该id的文档则更新,没有则新增),默认为全量更新(原来3个属性都有值,更新时只传两个属性,那么第三个属性会被置空)
PUT 索引库名/类型名/_id
{
"key":"value"
}
- 删除文档
DELETE 索引库名/类型名/_id
5.6 查询
5.6.1 基本查询
- 语法
GET 索引库名/类型名/_search
{
"query": {
"查询类型": {
"查询条件": "查询条件值"
}
}
}
这里query代表一个查询对象
查询类型:match_all,math,term,range等
查询条件:根据查询类型不同有较大的差异
5.6.1.1 查询所有match_all
- 语法
GET 索引库名/_search
{
"query": {
"match_all": {}
}
}
- EG
GET itheima/_search
{
"query": {
"match_all": {}
}
}
- 查询结果
{
"took": 3, # 查询花费时间,单位ms
"timed_out": false, 是否超时
"_shards": { 分片信息
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": { 搜索结果总览对象
"total": 4, 搜索到的总条数
"max_score": 1, 所有结果中文档得分的最高分
"hits": [ 搜索结果文档对象数组,每个元素是一条搜索到的文档信息
{
"_index": "itheima", 索引库
"_type": "_doc", 文档类型
"_id": "FdfauXMB7B8ED9LAPGn6", 文档id
"_score": 1, 文档得分
"_source": { 文档源数据
"title": "小米手机",
"images": "http://image.leyou.com/12479122.jpg",
"price": 2699
}
},
{
"_index": "itheima",
"_type": "_doc",
"_id": "1",
"_score": 1,
"_source": {
"title": "华为手机",
"images": "http://image.leyou.com/12479122.jpg",
"price": 4799
}
},
{
"_index": "itheima",
"_type": "_doc",
"_id": "OANswXMBIeDNWb4_bSfG",
"_score": 1,
"_source": {
"title": "小米电视4A",
"images": "http://image.leyou.com/12479122.jpg",
"price": 3899
}
},
{
"_index": "itheima",
"_type": "_doc",
"_id": "3",
"_score": 1,
"_source": {
"title": "超大米手机",
"images": "http://image.leyou.com/12479122.jpg",
"price": 3299,
"stock": 200,
"saleable": true,
"subTitle": "哈哈"
}
}
]
}
}
5.6.1.2 匹配查询match
- 语法
GET 索引库名/_search
{
"query":{
"match": {
"条件": "条件值"
}
}
}
- EG
GET itheima/_search
{
"query":{
"match": {
"title": "小米"
}
}
}
场景:查询分词的属性
默认情况下,会对用户输入的条件值进行分词然后使用or连接来查询.如用户输入""小米手机",会查询出"小米"、"手机"、"小米手机"的数据.
如需精确查找可以指定使用and连接,如下
- 条件值精确查找(类似不对用户输入分词)
# match指定指定对输入分词指定对输入分词使用连接
GET itheima/_search
{
"query":{
"match": {
"title":
{"query": "小米手机",
"operator": "and"
}
}
}
}
5.6.1.3 词条匹配term
- 语法
GET 索引库名/_search
{
"query":{
"term": {
"条件": "条件值"
}
}
}
-EG
GET itheima/_doc/_search
{
"query":{
"term": {
"price": 2699
}
}
}
适用条件:查询被用于精确值 匹配,这些精确值可能是数字、时间、布尔或者那些未分词的字符串 ,一般是在keyword上进行查询
需注意如果term查询的条件字段为string类型的,若这个字段做了分词,可能会查询不到如下
# 因为title为text类型,且进行了分词,形成的索引有"小米","电视","小米电视",但是没有"小米电视4A",无法进行精确匹配.所以对于分词的字段建议使用match
GET itheima/_search
{
"query": {
"term": {
"title": "小米电视4A"
}
}
}
5.6.1.4 bool组合
- 语法
must:多个查询条件完全匹配,相当于and
must_not:多个查询条件,必须完全不匹配,相当于not
should:多个查询条件做并集,相当于or
- EG
GET itheima/_search
{
"query": {
"bool": {
"must": {
"match": {
"title": "小米"
}
},
"must_not": {
"match": {
"title": "电视"
}
}
}
}
}
GET itheima/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "小米"
}
},
{
"match": {
"title": "手机"
}
}
]
}
}
}
5.6.1.5 范围查询 range
range 查询找出那些落在指定区间内的数字或者时间
- 语法
range
可以使用一下参数:
操作符 | 说明 |
---|---|
gte |
大于等于 |
gt |
大于 |
lte |
小于等于 |
lt |
小于 |
- EG
# 1000<price<3000
GET itheima/_search
{
"query": {
"range": {
"price": {
"gte": 1000,
"lte": 3000
}
}
}
}
5.6.1.6 模糊查询 fuzzy
-
场景,但只允许偏差值为2
elasticSearch_fuzzy.png - 语法
GET itheima/_search
{
"query": {
"fuzzy": {
"title": "电视3"
}
}
}
5.6.2 结果过滤
默认情况下,elasticsearch在搜索的结果中,会把文档中保存在 _source 的所有字段都返回。
如果我们只想获取其中的部分字段,我们可以添加 _source 的过滤
5.6.2.1 直接指定字段
-EG
GET itheima/_search
{
"_source": [
"title",
"price"
],
"query": {
"match": {
"title": "小米"
}
}
}
5.6.2.2 指定include和exclude
- EG
# include
GET itheima/_search
{
"_source": {
"includes": ["title","images"]
},
"query": {
"match": {
"title": "小米"
}
}
}
# exclude
GET itheima/_search
{
"_source": {
"excludes": "images"
},
"query": {
"match": {
"title": "小米"
}
}
}
5.6.3 filter过滤
注意过滤的字段不能分词,只能是keyword或数值类型
- eg:只能放在bool里,其他的查询都会对查询的结果评分造成影响,而filter不会
GET itheima/_search
{
"query": {
"bool": {
"filter": {
"range": {
"price": {
"gte": 1000,
"lte": 5000
}
}
}
}
}
}
5.6.4 排序
5.6.4.1 单字段排序
- EG
GET itheima/_search
{
"query": {
"match": {
"title": "小米"
}
},
"sort": [
{
"price": {
"order": "asc"
}
}
]
}
5.6.4.2 多字段排序
GET itheima/_search
{
"query": {
"match": {
"title": "手机"
}
},
"sort": [
{
"price": {
"order": "asc"
}
},{
"_score":{
"order": "desc"
}
}
]
}
5.6.5 分页
-EG
GET itheima/_search
{
"query": {
"match": {
"title": "手机"
}
},
"sort": [
{
"price": {
"order": "asc"
}
}
],
"from": 2, 开始位置(并非开始页)
"size": 2 每页大小
}
5.6.6 高亮
- 高亮原理:搜索结果中关键字加上约定好的标签
GET itheima/_search
{
"query": {
"match": {
"title": "手机"
}
},
"highlight": {
"pre_tags": "<em>",
"post_tags": "</em>",
"fields": {
"title": {}
}
}
}
5.7 聚合aggregations
聚合可以让我们极其方便的实现对数据的统计、分析。例如:
- 什么品牌的手机最受欢迎?
- 这些手机的平均价格、最高价格、最低价格?
- 这些手机每月的销售情况如何?
实现这些统计功能的比数据库的sql要方便的多,而且查询速度非常快,可以实现近实时搜索效果。
5.7.1 聚合的基本概念
桶(bucket) 类似于 group by
桶的作用,是按照某种方式对数据进行分组,每一组数据在ES中称为一个 桶 ,
例如我们根据国籍对人划分,可以得到 中国桶 、 英国桶 , 日本桶
或者我们按照年龄段对人进行划分:010,1020,2030,3040等。
Elasticsearch中提供的划分桶的方式有很多:
- Date Histogram Aggregation:根据日期阶梯分组,例如给定阶梯为周,会自动每周分为一组
- Histogram Aggregation:根据数值阶梯分组,与日期类似,需要知道分组的间隔(interval)
- Terms Aggregation:根据词条内容分组,词条内容完全匹配的为一组
- Range Aggregation:数值和日期的范围分组,指定开始和结束,然后按段分组
综上所述,我们发现bucket aggregations 只负责对数据进行分组,并不进行计算,因此往往bucket中
往往会嵌套另一种聚合:metrics aggregations即度量
度量(metrics) 相当于聚合的结果
分组完成以后,我们一般会对组中的数据进行聚合运算,例如求平均值、最大、最小、求和等,这些在
ES中称为 度量
比较常用的一些度量聚合方式:
- Avg Aggregation:求平均值
- Max Aggregation:求最大值
- Min Aggregation:求最小值
- Percentiles Aggregation:求百分比
- Stats Aggregation:同时返回avg、max、min、sum、count等
- Sum Aggregation:求和
- Top hits Aggregation:求前几
- Value Count Aggregation:求总数
5.7.2 测试
添加测试数据
PUT car
{
"mappings": {
"orders": {
"properties": {
"color": {
"type": "keyword"
},
"make": {
"type": "keyword"
}
}
}
}
}
POST car/orders/_bulk
{"index":{}}
{"price":10000,"color":"红","make":"本田","sold":"2014-10-28"}
{"index":{}}
{"price":20000,"color":"红","make":"本田","sold":"2014-11-05"}
{"index":{}}
{"price":30000,"color":"绿","make":"福特","sold":"2014-05-18"}
{"index":{}}
{"price":15000,"color":"蓝","make":"丰田","sold":"2014-07-02"}
{"index":{}}
{"price":12000,"color":"绿","make":"丰田","sold":"2014-08-19"}
{"index":{}}
{"price":20000,"color":"红","make":"本田","sold":"2014-11-05"}
{"index":{}}
{"price":80000,"color":"红","make":"宝马","sold":"2014-01-01"}
{"index":{}}
{"price":25000,"color":"蓝","make":"福特","sold":"2014-02-12"}
5.7.2.1 聚合为桶
- 按照颜色聚合为bucket
GET car/_search
{
"size": 0, //设置为0,不显示原文档,只显示聚合结果
"aggs": {
"popular_colors": {
"terms": {
"field": "color"
}
}
}
}
查询参数说明:
size: 查询条数,这里设置为0,因为我们不关心搜索到的数据,只关心聚合结果,提高效率
aggs:声明这是一个聚合查询,是aggregations的缩写
popular_colors:给这次聚合起一个名字,可任意指定。
terms:聚合的类型,这里选择terms,是根据词条内容(这里是颜色)划分
field:划分桶时依赖的字段
查询结果参数说明:
hits:查询结果为空,因为我们设置了size为0
aggregations:聚合的结果
popular_colors:我们定义的聚合名称
buckets:查找到的桶,每个不同的color字段值都会形成一个桶
key:这个桶对应的color字段的值
doc_count:这个桶中的文档数量
5.7.2.2 度量
前面的例子告诉我们每个桶里面的文档数量,这很有用。 但通常,我们的应用需要提供更复杂的文档度量。 例如,每种颜色汽车的平均价格是多少?因此,我们需要告诉Elasticsearch
使用哪个字段 ,使用何种度量方式 进行运算,这些信息要嵌套在 桶内,度量的运算会基于桶内的文档进行 .
GET car/_search
{
"size": 0,
"aggs": {
"popular_colors": {
"terms": {
"field": "color"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
参数说明:
aggs:我们在上一个aggs(popular_colors)内添加新的aggs。可见度量也是一个聚合
avg_price:聚合的名称
avg:度量的类型,这里是求平均值
field:度量运算的字段