Elastic Stack简介
如果你没有听说过Elastic Stack,那你一定听说过ELK,实际上ELK是三款软件的简称,分别是Elasticsearch、Logstash、Kibana组成,在发展的过程中,又有新成员Beats的加入,所以就形成了Elastic Stack。所以说,ELK是旧的称呼,Elastic Stack是新的名字。
全新的Elastic Stack技术栈包括:
- Elasticsearch
Elasticsearch 基于java,是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等。 - Logstash
Logstash 基于java,是一个开源的用于收集,分析和存储日志的工具。 - Kibana
Kibana 基于nodejs,也是一个开源和免费的工具,Kibana可以为 Logstash 和 ElasticSearch 提供的日志分析友好的 Web 界面,可以汇总、分析和搜索重要数据日志。 - Beats
Beats是elastic公司开源的一款采集系统监控数据的代理agent,是在被监控服务器上以客户端形式运行的数据收集器的统称,可以直接把数据发送给Elasticsearch或者通过Logstash发送给Elasticsearch,然后进行后续的数据分析活动。
Beats由如下组成:
1.Packetbeat:是一个网络数据包分析器,用于监控、收集网络流量信息,Packetbeat嗅探服务器之间的流量,解析应用层协议,并关联到消息的处理,其支持ICMP (v4 and v6)、DNS、HTTP、Mysql、PostgreSQL、Redis、MongoDB、Memcache等协议;
2.Filebeat:用于监控、收集服务器日志文件,其已取代 logstash forwarder;
3.Metricbeat:可定期获取外部系统的监控指标信息,其可以监控、收集 Apache、HAProxy、MongoDBMySQL、Nginx、PostgreSQL、Redis、System、Zookeeper等服务;
4.Winlogbeat:用于监控、收集Windows系统的日志信息;
Elasticsearch安装和使用
1.简介
ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。ElasticSearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便,官网:https://www.elastic.co/cn/pro...
2.安装
下载地址:https://www.elastic.co/cn/dow...
1)单机版安装
#创建jello用户,Elasticsearch不支持root用户运行
useradd jello
#将指定文件的拥有者改为指定的用户或组
chowm -R jello:jello /java
#解压安装包
tar -zxvf elasticsearch-6.5.4.tar.gz
#修改配置文件
vi config/elasticsearch.yml
network.host: 47.101.127.45 #绑定的地址
#说明:在Elasticsearch中如果,network.host不是localhost或者127.0.0.1的话,就会认为是生产环境,会对环境的要求比较高,我们的测试环境不一定能够满足,一般情况下需要修改2处配置,如下:
#1:修改jvm启动参数vi conf/jvm.options
-Xms128m#根据自己机器情况修改
-Xmx128m
#2:单个进程中的最大线程数vi /etc/sysctl.conf
vm.max_map_count=655360
修改完执行sysctl -p
#启动ES服务
cd bin
./elasticsearch 或 ./elasticsearch -d#后台系统
#通过访问http://47.101.127.45:9200进行测试,看到如下信息,就说明ES启动成功了
2.使用docker安装
#拉取镜像
docker pull elasticsearch:6.5.4
#创建容器
docker create --name elasticsearch --net host -e"discovery.type=single-node"-e"network.host=47.101.127.45" elasticsearch:6.5.4
#启动
docker start elasticsearch
#查看日志
docker logs --tail 10 elasticsearch
3.elasticsearch-head安装
由于ES官方并没有为ES提供界面管理工具,仅仅是提供了后台的服务。elasticsearch-head是一个为ES开发的一个页面客户端工具,其源码托管于GitHub,地址为:https://github.com/mobz/elast...,这里使用docker安装
#拉取镜像
docker pull mobz/elasticsearch-head:5
#创建容器
docker create --name elasticsearch-head -p 9100:9100 mobz/elasticsearch-head:5
#启动容器
docker start elasticsearch-head
通过浏览器进行访问:
注意:由于前后端分离开发,所以会存在跨域问题,需要在服务端做CORS的配置,如下:
vim elasticsearch.yml
http.cors.enabled: true
http.cors.allow-origin: "*"
若head连接Elasticsearch数据浏览模块不能显示数据,参考https://blog.csdn.net/qq_4110...
基本概念
1)索引
- 索引(index)是Elasticsearch对逻辑数据的逻辑存储,所以它可以分为更小的部分。
- 可以把索引看成关系型数据库的表,索引的结构是为快速有效的全文索引准备的,特别是它不存储原始值。
- 可以把Elasticsearch的索引看成MongoDB里的一个集合。
- Elasticsearch可以把索引存放在一台机器或者分散在多台服务器上,每个索引有一或多个分片(shard),每个分片可以有多个副本(replica)。
2)文档
- 存储在Elasticsearch中的主要实体叫文档(document)。用关系型数据库来类比的话,一个文档相当于数据库表中的一行记录。
- Elasticsearch和MongoDB中的文档类似,都可以有不同的结构,但Elasticsearch的文档中,相同字段必须有相同类型。
- 文档由多个字段组成,每个字段可能多次出现在一个文档里,这样的字段叫多值字段(multivalued)。
- 每个字段的类型,可以是文本、数值、日期等。字段类型也可以是复杂类型,一个字段包含其他子文档或者数组。
3)映射
所有文档写进索引之前都会先进行分析,如何将输入的文本分割为词条、哪些词条又会被过滤,这种行为叫做映射(mapping)。一般由用户自己定义规则。
4)文档类型
- 在Elasticsearch中,一个索引对象可以存储很多不同用途的对象。例如,一个博客应用程序可以保存文章和评论。
- 每个文档可以有不同的结构。
- 不同的文档类型不能为相同的属性设置不同的类型。例如,在同一索引中的所有文档类型中,一个叫title的字段必须具有相同的类型。
RESTful API
在Elasticsearch中,提供了功能丰富的RESTful API的操作,包括基本的CRUD、创建索引、删除索引等操作。
1)创建非结构化索引
在Lucene中,创建索引是需要定义字段名称以及字段的类型的,在Elasticsearch中提供了非结构化的索引,就是不需要创建索引结构,即可写入数据到索引中,实际上在Elasticsearch底层会进行结构化操作,此操作对用户是透明的。
#创建空索引
PUT http://47.101.127.45:9200/haoke
{
"settings": {
"index": {
"number_of_shards": "2",#分片数
"number_of_replicas": "0"#副本数
}
}
}
#响应结果
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "demo"
}
#删除索引
curl -XDELETE 'http://47.101.129.45:9200/haoke?pretty'
#响应结果
{
"acknowledged" : true
}
2.插入数据
URL规则:POST http://47.101.129.45:9200/{索引}/{类型}/{id}
curl -POST 'http://47.101.129.45:9200/haoke/user/1001?pretty' -H 'Content-Type: application/json' -d '{"id":1001,"name":"张三","age":20,"sex":"男"}'
#响应
{
"_index" : "haoke",
"_type" : "user",
"_id" : "1001",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 6,
"_primary_term" : 2
}
说明:非结构化的索引,不需要事先创建,直接插入数据默认创建索引。
#不指定id插入数据
curl -POST 'http://47.101.129.45:9200/haoke/user?pretty' -H 'Content-Type: application/json' -d '{"id":1002,"name":"张三","age":20,"sex":"男"}'
3.更新数据
在Elasticsearch中,文档数据是不为修改的,但是可以通过覆盖的方式进行更新。
curl -PUT 'http://47.101.129.45:9200/haoke/user/1001?pretty' -H 'Content-Type: application/json' -d '{"id":1001,"name":"张三","age":21,"sex":"女"}'
//响应
{
"_index" : "haoke",
"_type" : "user",
"_id" : "1001",
"_version" : 2, #版本号进行+1
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 7,
"_primary_term" : 2
}
可以看到数据已经被覆盖了。在内部,依然会查询到这个文档数据,然后进行覆盖操作,步骤如下:1. 从旧文档中检索JSON 2. 修改它 3. 删除旧文档 4. 索引新文档
#局部更新,注意:这里多了_update标识
curl -PUT 'http://47.101.129.45:9200/haoke/user/1001/_update?pretty' -H 'Content-Type: application/json' -d '{"doc":{"age":25}}'
#响应
{
"_index" : "haoke",
"_type" : "user",
"_id" : "1001",
"_version" : 3,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 8,
"_primary_term" : 2
}
4.删除数据
在Elasticsearch中,删除文档数据,只需要发起DELETE请求即可。
curl -XDELETE 'http://47.101.129.45:9200/haoke/user/1002?pretty'
#响应
{
"_index" : "haoke",
"_type" : "user",
"_id" : "1001",
"_version" : 4,
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 9,
"_primary_term" : 2
}
需要注意的是,result表示已经删除,version也更加了。如果删除一条不存在的数据,会响应404:
删除一个文档也不会立即从磁盘上移除,它只是被标记成已删除。Elasticsearch将会在你之后添加更多索引的时候才会在后台进行删除内容的清理。
5.搜索数据
#根据id搜索数据
curl -GET "http://47.101.129.45:9200/haoke/user/4xP3P24BpJzEX51oeOPv?pretty"
#响应
{
"_index" : "haoke",
"_type" : "user",
"_id" : "4xP3P24BpJzEX51oeOPv",
"_version" : 1,
"found" : true,
"_source" : {
"id" : 1002,
"name" : "张三",
"age" : 20,
"sex" : "男"
}
}
#搜索全部数据
curl -GET "http://47.101.129.45:9200/haoke/user/_search?pretty
#响应:(默认返回10条数据)
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 1.0,
"hits" : [
{
"_index" : "haoke",
"_type" : "user",
"_id" : "1001",
"_score" : 1.0,
"_source" : {
"id" : 1001,
"name" : "张三",
"age" : 20,
"sex" : "男"
}
},
{
"_index" : "haoke",
"_type" : "user",
"_id" : "4xP3P24BpJzEX51oeOPv",
"_score" : 1.0,
"_source" : {
"id" : 1002,
"name" : "张三",
"age" : 20,
"sex" : "男"
}
},
{
"_index" : "haoke",
"_type" : "user",
"_id" : "1003",
"_score" : 1.0,
"_source" : {
"id" : 1003,
"name" : "王五",
"age" : 30,
"sex" : "女"
}
}
]
}
}
#关键字搜素数据(查询年龄等于20的用户)
curl -GET "http://47.101.129.45:9200/haoke/user/_search?pretty&q=age:30"
#响应
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.0,
"hits" : [
{
"_index" : "haoke",
"_type" : "user",
"_id" : "1003",
"_score" : 1.0,
"_source" : {
"id" : 1003,
"name" : "王五",
"age" : 30,
"sex" : "女"
}
}
]
}
}
6.DSL搜索
Elasticsearch提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现
#match只是查询的一种
curl -POST "http://47.101.129.45:9200/haoke/user/_search?pretty" -H 'Content-Type: application/json' -d' {"query" : {"match" : {"age" : "20"}}}'
#查询年龄大于30岁的男性用户
curl -POST "http://47.101.129.45:9200/haoke/user/_search?pretty" -H 'Content-Type: application/json' -d '{"query": {"bool": {"filter": {"range": {"age": {"gt": 25}}},"must": {"match": {"sex": "女"}}}}}'
#全文搜索
curl -POST "http://47.101.129.45:9200/haoke/user/_search?pretty" -H 'Content-Type: application/json' -d '{"query" : {"match" : {"name" : "张三 李四"}}}'
7.高亮显示
curl -POST "http://47.101.129.45:9200/haoke/user/_search?pretty" -H 'Content-Type: application/json' -d '{"query" : {"match" : {"name" : "张三 李四"}},"highlight": {"fields": {"name": {}}}}'
8.聚合
在Elasticsearch中,支持聚合操作,类似SQL中的group by操作
curl -POST "http://47.101.129.45:9200/haoke/user/_search?pretty" -H 'Content-Type: application/json' -d '{"aggs": {"all_interests": {"terms": {"field": "age"}}}}'
{
"took" : 42,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 1.0,
"hits" : [
{
"_index" : "haoke",
"_type" : "user",
"_id" : "1001",
"_score" : 1.0,
"_source" : {
"id" : 1001,
"name" : "张三",
"age" : 20,
"sex" : "男"
}
},
{
"_index" : "haoke",
"_type" : "user",
"_id" : "4xP3P24BpJzEX51oeOPv",
"_score" : 1.0,
"_source" : {
"id" : 1002,
"name" : "张三",
"age" : 20,
"sex" : "男"
}
},
{
"_index" : "haoke",
"_type" : "user",
"_id" : "1003",
"_score" : 1.0,
"_source" : {
"id" : 1003,
"name" : "王五",
"age" : 30,
"sex" : "女"
}
}
]
},
"aggregations" : {
"all_interests" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : 20,
"doc_count" : 2
},
{
"key" : 30,
"doc_count" : 1
}
]
}
}
}
从结果可以看出,年龄20的有2条数据,30的有一条。
全文搜索
全文搜索两个最重要的方面是
- 相关性(Relevance)它是评价查询与其结果间的相关程度,并根据这种相关程度对结果排名的一种能力,这种计算方式可以是 TF/IDF 方法、地理位置邻近、模糊相似,或其他的某些算法。
- 分析(Analysis)它是将文本块转换为有区别的、规范化的 token 的一个过程,目的是为了创建倒排索引以及查询倒排索引。
1.构造数据
curl -PUT 'http://47.101.129.45:9200/test2?pretty' -H 'Content-Type: application/json' -d '{"settings": {"index": {"number_of_shards": "1","number_of_replicas": "0"}},"mappings": {"person": {"properties": {"name": {"type": "text"},"age": {"type": "integer"},"mail": {"type": "keyword"},"hobby": {"type": "text"}}}}}'
#批量插入数据
curl -X POST "http://47.101.129.45:9200/test2/person/_bulk?pretty" -H 'Content-Type: application/json' --data-binary '
{"index":{"_index":"test2","_type":"person"}}
{"name":"张三","age": 20,"mail": "111@qq.com","hobby":"羽毛球、乒乓球、足球"}
{"index":{"_index":"test2","_type":"person"}}
{"name":"李四","age": 21,"mail": "222@qq.com","hobby":"羽毛球、乒乓球、足球、篮球"}
{"index":{"_index":"test2","_type":"person"}}
{"name":"王五","age": 22,"mail": "333@qq.com","hobby":"羽毛球、篮球、游泳、听音乐"}
{"index":{"_index":"test2","_type":"person"}}
{"name":"赵六","age": 23,"mail": "444@qq.com","hobby":"跑步、游泳、篮球"}
{"index":{"_index":"test2","_type":"person"}}
{"name":"孙七","age": 24,"mail": "555@qq.com","hobby":"听音乐、看电影、羽毛球"}
'
2.单词搜索
curl -POST "http://47.101.129.45:9200/test2/person/_search?pretty" -H 'Content-Type: application/json' -d '{"query":{"match":{"hobby":"音乐"}},"highlight": {"fields": {"hobby": {}}}}'
#响应
{
"took" : 81,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.7182437,
"hits" : [
{
"_index" : "test2",
"_type" : "person",
"_id" : "QSJXfG4Bzkn4EUa6e__L",
"_score" : 1.7182437,
"_source" : {
"name" : "孙七",
"age" : 24,
"mail" : "555@qq.com",
"hobby" : "听音乐、看电影、羽毛球"
},
"highlight" : {
"hobby" : [
"听<em>音</em><em>乐</em>、看电影、羽毛球"
]
}
},
{
"_index" : "test2",
"_type" : "person",
"_id" : "PyJXfG4Bzkn4EUa6e__L",
"_score" : 1.6416124,
"_source" : {
"name" : "王五",
"age" : 22,
"mail" : "333@qq.com",
"hobby" : "羽毛球、篮球、游泳、听音乐"
},
"highlight" : {
"hobby" : [
"羽毛球、篮球、游泳、听<em>音</em><em>乐</em>"
]
}
}
]
}
}
过程说明:
- 检查字段类型
爱好 hobby 字段是一个 text 类型(指定了IK分词器),这意味着查询字符串本身也应该被分词。 - 分析查询字符串
将查询的字符串 “音乐” 传入IK分词器中,输出的结果是单个项音乐。因为只有一个单词项,所以 match 查询执行的是单个底层 term 查询 - 查找匹配文档
用 term 查询在倒排索引中查找 “音乐” 然后获取一组包含该项的文档 - 为每个文档评分
用 term 查询计算每个文档相关度评分 _score ,这是种将词频(term frequency,即词 “音乐” 在相关文档的hobby 字段中出现的频率)和反向文档频率(inverse document frequency,即词 “音乐” 在所有文档的hobby 字段中出现的频率),以及字段的长度(即字段越短相关度越高)相结合的计算方式。
3.多词搜索
curl -POST "http://47.101.129.45:9200/test2/person/_search?pretty" -H 'Content-Type: application/json' -d '{"query":{"match":{"hobby":"音乐 篮球"}},"highlight": {"fields": {"hobby": {}}}}'
#响应
{
"took" : 109,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 5,
"max_score" : 2.2613578,
"hits" : [
{
"_index" : "test2",
"_type" : "person",
"_id" : "PyJXfG4Bzkn4EUa6e__L",
"_score" : 2.2613578,
"_source" : {
"name" : "王五",
"age" : 22,
"mail" : "333@qq.com",
"hobby" : "羽毛球、篮球、游泳、听音乐"
},
"highlight" : {
"hobby" : [
"羽毛<em>球</em>、<em>篮</em><em>球</em>、游泳、听<em>音</em><em>乐</em>"
]
}
},
{
"_index" : "test2",
"_type" : "person",
"_id" : "QSJXfG4Bzkn4EUa6e__L",
"_score" : 1.8036304,
"_source" : {
"name" : "孙七",
"age" : 24,
"mail" : "555@qq.com",
"hobby" : "听音乐、看电影、羽毛球"
},
"highlight" : {
"hobby" : [
"听<em>音</em><em>乐</em>、看电影、羽毛<em>球</em>"
]
}
},
{
"_index" : "test2",
"_type" : "person",
"_id" : "QCJXfG4Bzkn4EUa6e__L",
"_score" : 0.7143588,
"_source" : {
"name" : "赵六",
"age" : 23,
"mail" : "444@qq.com",
"hobby" : "跑步、游泳、篮球"
},
"highlight" : {
"hobby" : [
"跑步、游泳、<em>篮</em><em>球</em>"
]
}
},
{
"_index" : "test2",
"_type" : "person",
"_id" : "PiJXfG4Bzkn4EUa6e__L",
"_score" : 0.6485575,
"_source" : {
"name" : "李四",
"age" : 21,
"mail" : "222@qq.com",
"hobby" : "羽毛球、乒乓球、足球、篮球"
},
"highlight" : {
"hobby" : [
"羽毛<em>球</em>、乒乓<em>球</em>、足<em>球</em>、<em>篮</em><em>球</em>"
]
}
},
{
"_index" : "test2",
"_type" : "person",
"_id" : "PSJXfG4Bzkn4EUa6e__L",
"_score" : 0.13880736,
"_source" : {
"name" : "张三",
"age" : 20,
"mail" : "111@qq.com",
"hobby" : "羽毛球、乒乓球、足球"
},
"highlight" : {
"hobby" : [
"羽毛<em>球</em>、乒乓<em>球</em>、足<em>球</em>"
]
}
}
]
}
}
可以看到,包含了“音乐”、“篮球”的数据都已经被搜索到了。可是,搜索的结果并不符合我们的预期,因为我们想搜索的是既包含“音乐”又包含“篮球”的用户,显然结果返回的“或”的关系。
在Elasticsearch中,可以指定词之间的逻辑关系,如下:
curl -POST "http://47.101.129.45:9200/test2/person/_search?pretty" -H 'Content-Type: application/json' -d '{"query":{"match":{"hobby":{"query":"音乐 篮球","operator":"and"}}},"highlight": {"fields": {"hobby": {}}}}'
#响应
{
"took" : 35,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 2.2613578,
"hits" : [
{
"_index" : "test2",
"_type" : "person",
"_id" : "PyJXfG4Bzkn4EUa6e__L",
"_score" : 2.2613578,
"_source" : {
"name" : "王五",
"age" : 22,
"mail" : "333@qq.com",
"hobby" : "羽毛球、篮球、游泳、听音乐"
},
"highlight" : {
"hobby" : [
"羽毛<em>球</em>、<em>篮</em><em>球</em>、游泳、听<em>音</em><em>乐</em>"
]
}
}
]
}
}
可以看到结果符合预期。
测试了“OR” 和 “AND”搜索,这是两个极端,其实在实际场景中,并不会选取这2个极端,更有可能是选取这种,或者说,只需要符合一定的相似度就可以查询到数据,在Elasticsearch中也支持这样的查询,通过minimum_should_match来指定匹配度,如:80%;
curl -POST "http://47.101.129.45:9200/test2/person/_search?pretty" -H 'Content-Type: application/json' -d '{"query":{"match":{"hobby":{"query":"音乐 篮球","minimum_should_match":"80%"}}},"highlight": {"fields": {"hobby": {}}}}'
相似度应该多少合适,需要在实际的需求中进行反复测试,才可得到合理的值。
4.组合搜索
在搜索时,也可以使用过滤器中讲过的bool组合查询
curl -POST "http://47.101.129.45:9200/test2/person/_search?pretty" -H 'Content-Type: application/json' -d '{"query":{"bool":{"must":{"match":{"hobby":"篮球"}},"must_not":{"match":{"hobby":"音乐"}},"should":[{"match": {"hobby":"游泳"}}]}},"highlight": {"fields": {"hobby": {}}}}'
#响应
{
"took" : 171,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 2.7124128,
"hits" : [
{
"_index" : "test2",
"_type" : "person",
"_id" : "QCJXfG4Bzkn4EUa6e__L",
"_score" : 2.7124128,
"_source" : {
"name" : "赵六",
"age" : 23,
"mail" : "444@qq.com",
"hobby" : "跑步、游泳、篮球"
},
"highlight" : {
"hobby" : [
"跑步、<em>游</em><em>泳</em>、<em>篮</em><em>球</em>"
]
}
},
{
"_index" : "test2",
"_type" : "person",
"_id" : "PiJXfG4Bzkn4EUa6e__L",
"_score" : 0.6485575,
"_source" : {
"name" : "李四",
"age" : 21,
"mail" : "222@qq.com",
"hobby" : "羽毛球、乒乓球、足球、篮球"
},
"highlight" : {
"hobby" : [
"羽毛<em>球</em>、乒乓<em>球</em>、足<em>球</em>、<em>篮</em><em>球</em>"
]
}
},
{
"_index" : "test2",
"_type" : "person",
"_id" : "PSJXfG4Bzkn4EUa6e__L",
"_score" : 0.13880736,
"_source" : {
"name" : "张三",
"age" : 20,
"mail" : "111@qq.com",
"hobby" : "羽毛球、乒乓球、足球"
},
"highlight" : {
"hobby" : [
"羽毛<em>球</em>、乒乓<em>球</em>、足<em>球</em>"
]
}
}
]
}
}
搜索结果中必须包含篮球,不能包含音乐,如果包含了游泳,那么它的相似度更高。
评分的计算规则
- bool 查询会为每个文档计算相关度评分 _score ,再将所有匹配的 must 和 should 语句的分数 _score 求和,最后除以 must 和 should 语句的总数
- must_not 语句不会影响评分,它的作用只是将不相关的文档排除。
默认情况下,should中的内容不是必须匹配的,如果查询语句中没有must,那么就会至少匹配其中一个。当然了,也可以通过minimum_should_match参数进行控制,该值可以是数字也可以的百分比。
curl -POST "http://47.101.129.45:9200/test2/person/_search?pretty" -H 'Content-Type: application/json' -d '{"query":{"bool":{"should":[{"match": {"hobby":" 游泳"}},{"match": {"hobby":"篮球"}},{"match": {"hobby":"音乐"}}],"minimum_should_match":2}},"highlight": {"fields": {"hobby": {}}}}'
#响应
{
"took" : 14,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 3.90297,
"hits" : [
{
"_index" : "test2",
"_type" : "person",
"_id" : "PyJXfG4Bzkn4EUa6e__L",
"_score" : 3.90297,
"_source" : {
"name" : "王五",
"age" : 22,
"mail" : "333@qq.com",
"hobby" : "羽毛球、篮球、游泳、听音乐"
},
"highlight" : {
"hobby" : [
"羽毛<em>球</em>、<em>篮</em><em>球</em>、<em>游</em><em>泳</em>、听<em>音</em><em>乐</em>"
]
}
},
{
"_index" : "test2",
"_type" : "person",
"_id" : "QCJXfG4Bzkn4EUa6e__L",
"_score" : 2.7124128,
"_source" : {
"name" : "赵六",
"age" : 23,
"mail" : "444@qq.com",
"hobby" : "跑步、游泳、篮球"
},
"highlight" : {
"hobby" : [
"跑步、<em>游</em><em>泳</em>、<em>篮</em><em>球</em>"
]
}
},
{
"_index" : "test2",
"_type" : "person",
"_id" : "QSJXfG4Bzkn4EUa6e__L",
"_score" : 1.8036304,
"_source" : {
"name" : "孙七",
"age" : 24,
"mail" : "555@qq.com",
"hobby" : "听音乐、看电影、羽毛球"
},
"highlight" : {
"hobby" : [
"听<em>音</em><em>乐</em>、看电影、羽毛<em>球</em>"
]
}
}
]
}
}
minimum_should_match为2,意思是should中的三个词,至少要满足2个。
5.权重
有些时候,我们可能需要对某些词增加权重来影响该条数据的得分。如下:
搜索关键字为“游泳篮球”,如果结果中包含了“音乐”权重为10,包含了“跑步”权重为2。
curl -POST "http://47.101.129.45:9200/test2/person/_search?pretty" -H 'Content-Type: application/json' -d '{"query": {"bool": {"must": {"match": {"hobby": {"query": "游泳篮球","operator": "and"}}},"should": [{"match": {"hobby": {"query": "音乐","boost": 10}}},{"match": {"hobby": {"query": "跑步","boost": 2}}}]}},"highlight": {"fields": {"hobby": {}}}}'
#响应
{
"took" : 15,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 18.677483,
"hits" : [
{
"_index" : "test2",
"_type" : "person",
"_id" : "PyJXfG4Bzkn4EUa6e__L",
"_score" : 18.677483,
"_source" : {
"name" : "王五",
"age" : 22,
"mail" : "333@qq.com",
"hobby" : "羽毛球、篮球、游泳、听音乐"
},
"highlight" : {
"hobby" : [
"羽毛<em>球</em>、<em>篮</em><em>球</em>、<em>游</em><em>泳</em>、听<em>音</em><em>乐</em>"
]
}
},
{
"_index" : "test2",
"_type" : "person",
"_id" : "QCJXfG4Bzkn4EUa6e__L",
"_score" : 9.040203,
"_source" : {
"name" : "赵六",
"age" : 23,
"mail" : "444@qq.com",
"hobby" : "跑步、游泳、篮球"
},
"highlight" : {
"hobby" : [
"<em>跑</em><em>步</em>、<em>游</em><em>泳</em>、<em>篮</em><em>球</em>"
]
}
}
]
}
}
6.短语匹配
在Elasticsearch中,短语匹配意味着不仅仅是词要匹配,并且词的顺序也要一致
curl -POST "http://47.101.129.45:9200/test2/person/_search?pretty" -H 'Content-Type: application/json' -d '{"query":{"match_phrase":{"hobby":{"query":"羽毛球篮球"}}},"highlight": {"fields": {"hobby": {}}}}'
#响应
{
"took" : 80,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.2079394,
"hits" : [
{
"_index" : "test2",
"_type" : "person",
"_id" : "PyJXfG4Bzkn4EUa6e__L",
"_score" : 1.2079394,
"_source" : {
"name" : "王五",
"age" : 22,
"mail" : "333@qq.com",
"hobby" : "羽毛球、篮球、游泳、听音乐"
},
"highlight" : {
"hobby" : [
"<em>羽</em><em>毛</em><em>球</em>、<em>篮</em><em>球</em>、游泳、听音乐"
]
}
}
]
}
}
如果觉得这样太过于苛刻,可以增加slop参数,允许跳过N个词进行匹配
curl -POST "http://47.101.129.45:9200/test2/person/_search?pretty" -H 'Content-Type: application/json' -d '{"query":{"match_phrase":{"hobby":{"query":"羽毛球足球","slop":3}}},"highlight": {"fields": {"hobby": {}}}}'
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。