文章目录
1. Elasticsearch 产生背景
1.1 大规模数据如何检索
如:当系统数据量上了10亿、100亿条的时候,在做系统架构的时候通常会从以下角度去考虑问题:
1)用什么数据库好?(mysql、oracle、mongodb、hbase…)
2)如何解决单点故障;(lvs、F5、A10、Zookeeper、MQ)
3)如何保证数据安全性;(热备、冷备、异地多活)
4)如何解决检索难题;(数据库代理中间件:mysql-proxy、Cobar、MaxScale等;)
5)如何解决统计分析问题;(离线、近实时)
1.2 传统数据库的应对解决方案
对于关系型数据,我们通常采用以下或类似架构去解决查询瓶颈和写入瓶颈:
解决要点:
1)通过主从备份解决数据安全性问题;
2)通过数据库代理中间件心跳监测,解决单点故障问题;
3)通过代理中间件将查询语句分发到各个slave节点进行查询,并汇总结果
1.3 非关系型数据库解决方案
对于Nosql数据库,以mongodb为例,其它原理类似:
解决要点:
1)通过副本备份保证数据安全性;
2)通过节点竞选机制解决单点问题;
3)先从配置库检索分片信息,然后将请求分发到各个节点,最后由路由节点合并汇总结果
1.4 内存数据库解决方案
完全把数据放在内存中是不可靠的,实际上也不太现实,当我们的数据达到PB级别时,按照每个节点96G内存计算,在内存完全装满的数据情况下,需要的机器是:1PB=1024T=1048576G
节点数=1048576/96=10922个
实际上,考虑到数据备份,节点数往往在2.5万台左右。成本巨大决定了其不现实!
所以把数据放在内存也好,不放在内存也好,都不能完完全全解决问题。
全部放在内存速度问题是解决了,但成本问题上来了。
为解决以上问题,从源头着手分析,通常会从以下方式来寻找方法:
1、存储数据时按有序存储;
2、将数据和索引分离;
3、压缩数据;
这就引出了 Elasticsearch
2. Elasticsearch 介绍
Elasticsearch 是一个基于Lucene的分布式搜索和分析引擎。
ES是elaticsearch简写, Elasticsearch是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。
Elasticsearch使用Java开发,在Apache许可条款下开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便
使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,使得全文检索变得简单
设计用途:用于分布式全文检索,通过HTTP使用JSON进行数据索引,速度快
2.1 Lucene与Elasticsearch关系
1)Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。
2)Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
2.2 Elasticsearch核心概念
Cluster:集群
ES可以作为一个独立的单个搜索服务器。不过,为了处理大型数据集,实现容错和高可用性,ES可以运行在许多互相合作的服务器上。这些服务器的集合称为集群。
Node:节点
形成集群的每个服务器称为节点。
Shard:分片
当有大量的文档时,由于内存的限制、磁盘处理能力不足、无法足够快的响应客户端的请求等,一个节点可能不够。这种情况下,数据可以分为较小的分片。每个分片放到不同的服务器上。
当你查询的索引分布在多个分片上时,ES会把查询发送给每个相关的分片,并将结果组合在一起,而应用程序并不知道分片的存在。即:这个过程对用户来说是透明的。
Replia:副本
为提高查询吞吐量或实现高可用性,可以使用分片副本。
副本是一个分片的精确复制,每个分片可以有零个或多个副本。ES中可以有许多相同的分片,其中之一被选择更改索引操作,这种特殊的分片称为主分片。
当主分片丢失时,如:该分片所在的数据不可用时,集群将副本提升为新的主分片。
全文检索
全文检索就是对一篇文章进行索引,可以根据关键字搜索,类似于mysql里的like语句。
全文索引就是把内容根据词的意义进行分词,然后分别创建索引,例如”今日是周日我们出去玩” 可能会被分词成:“今天“,”周日“,“我们“,”出去玩“ 等token,这样当你搜索“周日” 或者 “出去玩” 都会把这句搜出来。
2.3 与关系型数据库Mysql对比
- 关系型数据库中的数据库(DataBase),等价于ES中的索引(Index)
- 一个数据库下面有N张表(Table),等价于1个索引Index下面有N多类型(Type),
- 一个数据库表(Table)下的数据由多行(ROW)多列(column,属性)组成,等价于1个Type由多个文档(Document)和多Field组成。
- 在一个关系型数据库里面,schema定义了表、每个表的字段,还有表和字段之间的关系。 与之对应的,在ES中:Mapping定义索引下的Type的字段处理规则,即索引如何建立、索引类型、是否保存原始索引JSON文档、是否压缩原始JSON文档、是否需要分词处理、如何进行分词处理等。
- 在数据库中的增insert、删delete、改update、查search操作等价于ES中的增PUT/POST、删Delete、改_update、查GET.1.7
2.4 ES逻辑设计(文档–>类型–>索引)
一个索引类型中,包含多个文档,比如说文档1,文档2。
当我们索引一篇文档时,可以通过这样的顺序找到它:索引 ▷ 类型 ▷文档ID,通过这个组合我们就能索引到某个具体的文档。
注意:ID不必是整数,实际上它是个字符串。
文档
之前说elasticsearch是面向文档的,那么就意味着索引和搜索数据的最小单位是文档,elasticsearch中,文档有几个重要属性:
- 自我包含,一篇文档同时包含字段和对应的值,也就是同时包含key:value
- 可以是层次型的,一个文档中包含自文档,复杂的逻辑实体就是这么来的
- 灵活的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,在elasticsearch中,对于字段是非常灵活的,有时候,我们可以忽略该字段,或者动态的添加一个新的字段。
- 文档是无模式的,也就是说,字段对应值的类型可以是不限类型的。
尽管我们可以随意的新增或者忽略某个字段,但是,每个字段的类型非常重要,比如一个年龄字段类型,可以是字符串也可以是整型。因为elasticsearch会保存字段和类型之间的映射及其他的设置。这种映射具体到每个映射的每种类型(详见扩展阅读:17-扩展阅读-删除映射类型.md),这也是为什么在elasticsearch中,类型有时候也称为映射类型。
类型
1、类型是文档的逻辑容器,就像关系型数据库一样,表格是行的容器。
2、类型中对于字段的定义称为映射,比如name映射为字符串类型。
3、我们说文档是无模式的,它们不需要拥有映射中所定义的所有字段,比如新增一个字段,是怎么做的呢?elasticsearch会自动的将新字段加入映射,但是这个字段的不确定它是什么类型,elasticsearch就开始猜,如果这个值是18,那么elasticsearch会认为它是整型。
4、但是elasticsearch也可能猜不对,所以最安全的方式就是提前定义好所需要的映射,这点跟关系型数据库殊途同归了,先定义好字段,然后再使用,别整什么幺蛾子。后面在讨论更多关于映射的东西。
索引
索引是映射类型的容器,elasticsearch中的索引是一个非常大的文档集合。索引存储了映射类型的字段和其他设置。然后它们被存储到了各个分片上了。
2.5 ES物理设计
一个集群包含至少一个节点,而一个节点就是一个elasticsearch进程。节点内可以有多个索引。
默认的,如果你创建一个索引,那么这个索引将会有5个分片(primary shard,又称主分片)构成,而每个分片又有一个副本(replica shard,又称复制分片),这样,就有了10个分片。
那么这个索引是如何存储在集群中的呢?
图中有3个节点的集群,可以看到主分片和对应的复制分片都不会在同一个节点内,这样有利于某个节点挂掉了,数据也不至于丢失。
实际上,一个分片是一个Lucene索引,一个包含倒排索引的文件目录,倒排索引的结构使得elasticsearch在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的关键字
2.6 ELK是什么
ELK=elasticsearch+Logstash+kibana
elasticsearch:后台分布式存储以及全文检索
logstash: 日志加工、“搬运工”
kibana:数据可视化展示。
ELK架构为数据分布式存储、可视化查询和日志解析创建了一个功能强大的管理链。 三者相互配合,取长补短,共同完成分布式大数据处理工作。
2.7 Elasticsearch特点和优势
1)分布式实时文件存储,可将每一个字段存入索引,使其可以被检索到。
2)实时分析的分布式搜索引擎。
分布式:索引分拆成多个分片,每个分片可有零个或多个副本。集群中的每个数据节点都可承载一个或多个分片,并且协调和处理各种操作;
负载再平衡和路由在大多数情况下自动完成。
3)可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。也可以运行在单台PC上(已测试)
4)支持插件机制,分词插件、同步插件、Hadoop插件、可视化插件等。
2.8 Elasticsearch 业务场景
实际项目开发实战中,几乎每个系统都会有一个搜索的功能,当搜索做到一定程度时,维护和扩展起来难度就会慢慢变大,所以很多公司都会把搜索单独独立出一个模块,用ElasticSearch等来实现。
近年ElasticSearch发展迅猛,已经超越了其最初的纯搜索引擎的角色,现在已经增加了数据聚合分析(aggregation)和可视化的特性,如果你有数百万的文档需要通过关键词进行定位时,ElasticSearch肯定是最佳选择。当然,如果你的文档是JSON的,你也可以把ElasticSearch当作一种“NoSQL数据库”, 应用ElasticSearch数据聚合分析(aggregation)的特性,针对数据进行多维度的分析。
尝试使用ES来替代传统的NoSQL,它的横向扩展机制太方便了
应用场景:
1)新系统开发尝试使用ES作为存储和检索服务器;
2)现有系统升级需要支持全文检索服务,需要使用ES
2.9 Elasticsearch 索引到底能处理多大数据
单一索引的极限取决于存储索引的硬件、索引的设计、如何处理数据以及你为索引备份了多少副本。
通常来说,一个Lucene索引(也就是一个elasticsearch分片,一个es索引默认5个分片)不能处理多于21亿篇文档,或者多于2740亿的唯一词条。但达到这个极限之前,我们可能就没有足够的磁盘空间了!
当然,一个分片如何很大的话,读写性能将会变得非常差
3. ElasticSearch 安装
3.1 安装 ElasticSearch
一、 安装JDK环境
因为ElasticSearch是用Java语言编写的,所以必须安装JDK的环境,并且是JDK 1.8以上
官方网址:https://www.oracle.com/java/technologies/downloads/
安装完成查看java版本
java -version
二、 官网下载elasticsearch
官方网站:https://www.elastic.co/cn/downloads/elasticsearch
三、 启动 es
1. 下载完成后解压并在cmd中切换到bin路径下
cd elasticsearch-<version>/bin
2. 启动es,在 cmd 中输入 elasticsearch 启动。如果是在 Windows 上面运行 Elasticseach,应该
运行 bin/elasticsearch.bat 而不是 bin/elasticsearch
启动完可以测试,如下所示:
在浏览器输入以下地址:http://127.0.0.1:9200/,可以看到以下内容
如果在运行中出现如下异常
只需要将 elasticsearch-7.5.0\config\elasticsearch.keystore.tmp 文件删除即可
3.2 关闭 es
# 查看进程
ps -ef | grep elastic
# 干掉进程
kill -9 2382(进程号)
# 以守护进程方式启动es
elasticsearch -d
4. Elasticsearch 插件介绍
es插件是一种增强Elasticsearch核心功能的途径。它们可以为es添加自定义映射类型、自定义分词器、原生脚本、自伸缩等等扩展功能。
es插件包含JAR文件,也可能包含脚本和配置文件,并且必须在集群中的每个节点上安装。安装之后,需要重启集群中的每个节点才能使插件生效。
es插件包含核心插件和第三方插件两种
4.1 核心插件
核心插件是elasticsearch项目提供的官方插件,都是开源项目。这些插件会跟着elasticsearch版本升级进行升级,总能匹配到对应版本的elasticsearch,这些插件是有官方团队和社区成员共同开发的。
官方插件地址: https://github.com/elastic/elasticsearch/tree/master/plugins
4.2 第三方插件
第三方插件是有开发者或者第三方组织自主开发便于扩展elasticsearch功能,它们拥有自己的许可协议,在使用它们之前需要清除插件的使用协议,不一定随着elasticsearch版本升级, 所以使用者自行辨别插件和es的兼容性。
4.3 插件安装
elasticsearch的插件安装方式还是很方便易用的。
它包含了命令行,url,离线安装三种方式。
核心插件随便选择一种方式安装均可,第三方插件建议使用离线安装方式
第一种:命令行
bin/elasticsearch-plugin install [plugin_name]
# bin/elasticsearch-plugin install analysis-smartcn 安装中文分词器
第二种:url安装
bin/elasticsearch-plugin install [url]
# bin/elasticsearch-plugin install https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-6.4.0.zip
第三种:离线安装
#https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-6.4.0.zip
# 点击下载analysis-smartcn离线包
# 将离线包解压到ElasticSearch 安装目录下的 plugins 目录下
# 重启es。新装插件必须要重启es
注意:插件的版本要与 ElasticSearch 版本要一致
5. ElasticSearch 之 ElasticSearch-head
elasticsearch-head 是 elasticsearch 的一款可视化工具,依赖于 node.js ,所以需要先安装 node.js
5.1 安装 Node.js
略
5.2 安装 Grunt
# Grunt是基于Node.js的项目构建工具。它可以自动运行你所设定的任务
npm install grunt -g
5.3 下载 Head
官网:https://github.com/mobz/elasticsearch-head
# 解压后切换到目录下
cd elasticsearch-head
# 通过npm安装依赖
npm install
# 启动
npm run start
# 在浏览器里打开,界面如下所示
http://localhost:9100/
5.4 配置跨域
修改 Elasticsearch 安装目录中 config 文件夹下 elasticsearch.yml 文件,加入下面两行:
添加配置时,:后必须空格,不然启动闪退
http.cors.enabled: true
http.cors.allow-origin: "*"
启动 Elasticsearch ,如下页面即为成功
6. ElasticSearch 安装 Kibana
6.1 Kibana 介绍
Kibana 是一款开源的数据分析和可视化平台,它是 Elastic Stack 成员之一,设计用于和 Elasticsearch 协作。
您、可以使用 Kibana 对 Elasticsearch 索引中的数据进行搜索、查看、交互操作。
可以很方便的利用图表、表格及地图对数据进行多元化的分析和呈现
详情可见用户手册:
https://www.elastic.co/guide/cn/kibana/current/index.html
注意跟Elasticsearch版本兼容情况,详情见:
https://www.elastic.co/cn/support/matrix#matrix_compatibility
下载地址为:
https://www.elastic.co/cn/downloads/past-releases
6.2 下载 Kibana
到相应地址,下载即可,解压下载后的文件
6.3 修改配置文件
修改配置文件:vim 安装目录 /config/kibana.yml
# 更多配置信息,详见 https://www.elastic.co/guide/cn/kibana/current/settings.html
server.port: 5601
server.host: "127.0.0.1"
server.name: lqz
elasticsearch.hosts: ["http://localhost:9200/"]
6.4 启动
到安装目录下:
./bin/kibana
# 正常启动
6.5 查看
在浏览器里访问:http://localhost:5601/app/kibana
(如访问不到,尝试删除es中跟kibana相关的索引)
选择 Dev Tools
在 console 中输入 GET _settings ,查询可以看到如下
7. Elasticsearch 之 索引操作
具体操作可以查看官方文档
https://www.elastic.co/guide/en/elasticsearch/reference/7.5/indices.html>
官方2版本的中文文档
https://www.elastic.co/guide/cn/elasticsearch/guide/current/index-settings.html
7.1 索引初始化
# 新建一个x1的索引,索引分片数量为5,索引副本数量为1
PUT x1
{
"settings": {
"index":{
"number_of_shards":5,
"number_of_replicas":1
}
}
}
'''
number_of_shards
每个索引的主分片数,默认值是 5 。这个配置在索引创建后不能修改。
number_of_replicas
每个主分片的副本数,默认值是 1 。对于活动的索引库,这个配置可以随时修改。
'''
# 获取x2索引的配置信息
GET x2/_settings
# 获取所有索引的配置信息
GET _all/_settings
# 同上
GET _settings
7.2 更新索引
# 修改索引副本数量为2
PUT x2/_settings
{
"number_of_replicas": 2
}
# 如遇到报错:cluster_block_exception
# 这是因为由于ES新节点的数据目录data存储空间不足,导致从master主节点接收同步数据的时候失败,此时ES集群为了保护数据,会自动把索引分片index置为只读read-only
PUT _all/_settings
{
"index": {
"blocks": {
"read_only_allow_delete": false
}
}
}
7.3 删除索引
# 删除x2索引
DELETE x2
8. Elasticsearch 之 映射管理
在Elasticsearch 6.0.0或更高版本中创建的索引只包含一个mapping type。 在5.x中使用multiple mapping types创建的索引将继续像以前一样在Elasticsearch 6.x中运行。 Mapping types将在Elasticsearch 7.0.0中完全删除
8.1 映射介绍
在创建索引的时候,可以预先定义字段的类型及相关属性
Es会根据Json数据源的基础类型,猜测你想要映射的字段,将输入的数据转变成可以搜索的索引项。
Mapping是我们自己定义的字段数据类型,同时告诉es如何索引数据及是否可以被搜索
作用:会让索引建立的更加细致和完善
mysql中有建表语句,es中就是映射管理,即便没有类型,文档可以直接插入
8.2 字段数据类型
类型 | 说明 |
---|---|
string类型 | text,keyword |
数字类型 | long,integer,short,byte,double,float |
日期类型 | data |
布尔类型 | boolean |
binary类型 | binary |
复杂类型 | object(实体,对象),nested(列表) |
geo类型 | geo-point,geo-shape(地理位置) |
专业类型 | ip,competion(搜索建议) |
8.3 映射参数
属性 | 描述 | 适合类型 |
---|---|---|
store | 值为yes表示存储,no表示不存储,默认为yes | all |
index | yes表示分析,no表示不分析,默认为true | text |
null_value | 如果字段为空,可以设置一个默认值,比如"NA"(传过来为空,不能搜索,na可以搜索) | all |
analyzer | 可以设置索引和搜索时用的分析器,默认使用的是standard分析器,还可以使用whitespace,simple。都是英文分析器 | all |
include_in_all | 默认es为每个文档定义一个特殊域_all,它的作用是让每个字段都被搜索到,如果想让某个字段不被搜索到,可以设置为false | all |
format | 时间格式字符串模式 | date |
8.4 创建索引
text 类型会取出词做倒排索引,keyword 不会被分词,原样存储,原样匹配
mapping 类型一旦确定,以后就不能修改了
# 6.x的版本没问题
PUT books
{
"mappings": {
"book":{
"properties":{
"title":{
"type":"text",
"analyzer": "ik_max_word"
},
"price":{
"type":"integer"
},
"addr":{
"type":"keyword"
},
"company":{
"properties":{
"name":{"type":"text"},
"company_addr":{"type":"text"},
"employee_count":{"type":"integer"}
}
},
"publish_date":{"type":"date","format":"yyy-MM-dd"}
}
}
}
}
7.x 版本以后
# 7.x及以上,6.x以后,强制一个索引下只能有一个类型,叫_doc (一个数据库只能建一个表)
PUT books
{
"mappings": {
"properties":{
"title":{
"type":"text"
},
"price":{
"type":"integer"
},
"addr":{
"type":"keyword"
},
"company":{
"properties":{
"name":{"type":"text"},
"company_addr":{"type":"text"},
"employee_count":{"type":"integer"}
}
},
"publish_date":{"type":"date","format":"yyy-MM-dd"}
}
}
}
# 插入文档
PUT books/_doc/1
{
"title":"大头儿子小偷爸爸",
"price":100,
"addr":"北京天安门",
"company":{
"name":"我爱北京天安门",
"company_addr":"我的家在东北松花江傻姑娘",
"employee_count":10
},
"publish_date":"2019-08-19"
}
# 测试数据2
PUT books/_doc/2
{
"title":"白雪公主和十个小矮人",
"price":"99", # 写字符串会自动转换
"addr":"黑暗森里",
"company":{
"name":"我的家乡在上海",
"company_addr":"朋友一生一起走",
"employee_count":10
},
"publish_date":"2018-05-19"
}
PUT books/_doc/3 # 这个也可以存
{
"age":"白雪公主和十个小矮人",
"name":"xwx"
}
8.5 查看索引
# 查看books索引的mapping
GET books/_mapping
# 获取所有的mapping
GET _all/_mapping
9. Elasticsearch 的增删查改(CURD)
9.1 CURD 之 Create
PUT xwx/_doc/1
{
"name":"顾老二",
"age":30,
"from": "gu",
"desc": "皮肤黑、武器长、性格直",
"tags": ["黑", "长", "直"]
}
PUT xwx/_doc/2
{
"name":"熊大",
"age":22,
"from": "ha",
"desc": "小熊一只",
"tags": ["黄", "大"]
}
注意:当执行PUT命令时,如果数据不存在,则新增该条数据,如果数据存在则修改该条数据。
咱们通过GET命令查询一下:
GET xwx/_doc/1
如果使用 PUT 方式来修改,结果如下所示,会将原本的数据代替导致数据缺失
PUT xwx/_doc/1
{
"desc":"皮肤很黄,武器很长,性格很直",
"tags":["很黄","很长", "很直"]
}
9.2 CURD 之 Update
上面出现的问题,我们先恢复成原装。
PUT xwx/_doc/1
{
"name":"顾老二",
"age":30,
"from": "gu",
"desc": "皮肤黑、武器长、性格直",
"tags": ["黑", "长", "直"]
}
接下来修改需要使用 POST 方法,如下所示,原本的数据不会缺失
POST xwx/_doc/1/_update
{
"doc": {
"desc": "这是修改后",
"tags": ["哈哈","哈哈", "哈哈"]
}
}
现在推荐的写法如下所示
POST /xwx/_update/1
{
"doc": {
"desc": "这是推荐的写法",
"tags": ["哈哈","哈哈", "哈哈"]
}
}
9.3 CURD 之 Delete
DELETE xwx/_doc/1
通过DELETE
命令,就可以删除掉
# 再次获取数值
GET xwx/_doc/1
# found:false 表示查询数据不存在
{
"_index" : "xwx",
"_type" : "_doc",
"_id" : "1",
"found" : false
}
9.4 CURD 之 Retrieve
我们上面已经不知不觉的使用熟悉这种简单查询方式,通过 GET命令查询指定文档:
GET xwx/_doc/1
10. Elasticsearch 之查询的两种方式
-
查询字符串(query string),简单查询,就像是像传递URL参数一样去传递查询语句,被称为简单搜索或查询字符串(query string)搜索。
-
另外一种是通过DSL语句来进行查询,被称为DSL查询(Query DSL),DSL是Elasticsearch提供的一种丰富且灵活的查询语言,该语言以json请求体的形式出现,通过restful请求与Elasticsearch进行交互。
数据准备
PUT xwx/_doc/1
{
"name":"顾老二",
"age":30,
"from": "gu",
"desc": "皮肤黑、武器长、性格直",
"tags": ["黑", "长", "直"]
}
PUT xwx/_doc/2
{
"name":"大娘子",
"age":18,
"from":"sheng",
"desc":"肤白貌美,娇憨可爱",
"tags":["白", "富","美"]
}
PUT xwx/_doc/3
{
"name":"龙套偏房",
"age":22,
"from":"gu",
"desc":"mmp,没怎么看,不知道怎么形容",
"tags":["造数据", "真","难"]
}
PUT xwx/_doc/4
{
"name":"石头",
"age":29,
"from":"gu",
"desc":"粗中有细,狐假虎威",
"tags":["粗", "大","猛"]
}
PUT xwx/_doc/5
{
"name":"魏行首",
"age":25,
"from":"广云台",
"desc":"仿佛兮若轻云之蔽月,飘飘兮若流风之回雪,mmp,最后竟然没有嫁给顾老二!",
"tags":["闭月","羞花"]
}
10.1 查询字符串
GET xwx/_doc/_search?q=from:gu
还是使用 GET 命令,通过 _serarch
查询,查询条件是什么呢?条件是 from 属性 是 gu 的人都有哪些。别忘了_search 和 from 属性中间的英文分隔符?
,结果如下
#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
"took" : 19,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 0.6329006,
"hits" : [
{
"_index" : "xwx",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.6329006,
"_source" : {
"name" : "顾老二",
"age" : 30,
"from" : "gu",
"desc" : "皮肤黑、武器长、性格直",
"tags" : [
"黑",
"长",
"直"
]
}
},
{
"_index" : "xwx",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.6329006,
"_source" : {
"name" : "龙套偏房",
"age" : 22,
"from" : "gu",
"desc" : "mmp,没怎么看,不知道怎么形容",
"tags" : [
"造数据",
"真",
"难"
]
}
},
{
"_index" : "xwx",
"_type" : "_doc",
"_id" : "4",
"_score" : 0.6329006,
"_source" : {
"name" : "石头",
"age" : 29,
"from" : "gu",
"desc" : "粗中有细,狐假虎威",
"tags" : [
"粗",
"大",
"猛"
]
}
}
]
}
}
我们来重点说下hits
,hits 是返回的结果集(如上是所有 from 属性为 gu 的结果集)。重点中的重点是 _score
得分,得分是什么呢?根据算法算出跟查询条件的匹配度,匹配度高得分就高。
10.2 结构化查询
现在使用DSL
方式,来完成刚才的查询
GET xwx/_doc/_search
{
"query": {
"match": {
"from": "gu"
}
}
}
上例,查询条件是一步步构建出来的,将查询条件添加到 match
中即可,而 match 则是查询所有 from字段的值中含有 gu 的结果就会返回。
11 term 与 match 查询
11.1 match 系列之 match(按条件查询)
match 查询如下所示
GET xwx/_doc/_search
{
"query": {
"match": {
"from": "gu"
}
}
}
11.2 match 系列之 match_all(查询全部)
除了按条件查询之外,我们还可以查询 xwx
索引下的 doc 类型中的所有文档,那就是查询全部
GET xwx/_doc/_search
{
"query": {
"match_all": {}
}
}
match_all 的值为空,表示没有查询条件,那就是查询全部。就像 select * from table_name
一样
11.2 match 系列之 match_phrase(短语查询)
现在已经对 match 有了基本的了解,match 查询的是散列映射,包含了我们希望搜索的字段和字符串。也就说,只要文档中只要有我们希望的那个关键字,但也因此带来了一些问题。
首先来创建一些示例:
PUT t1/_doc/1
{
"title": "中国是世界上人口最多的国家"
}
PUT t1/_doc/2
{
"title": "目前美国是世界上军事实力最强大的国家"
}
PUT t1/_doc/3
{
"title": "北京是中国的首都"
}
现在,当我们以 中国
作为搜索条件,我们希望只返回和中国相关的文档。首先来使用 match 查询:
GET t1/_doc/_search
{
"query": {
"match": {
"title": "中国"
}
}
}
结果如下所示,虽然如期的返回了中国的文档。但是却把和美国的文档也返回了
因为这是 elasticsearch 在内部对文档做分词的时候,对于中文来说,就是一个字一个字分的,所以,我们搜 中国
,中
和国
都符合条件,返回,而美国的国
也符合。
#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 0.71622837,
"hits" : [
{
"_index" : "t1",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.71622837,
"_source" : {
"title" : "北京是中国的首都"
}
},
{
"_index" : "t1",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.6536093,
"_source" : {
"title" : "中国是世界上人口最多的国家"
}
},
{
"_index" : "t1",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.1656832,
"_source" : {
"title" : "目前美国是世界上军事实力最强大的国家"
}
}
]
}
}
而我们认为中国
是个短语,是一个有具体含义的词。所以elasticsearch在处理中文分词方面比较弱势。后面会有对中文的插件。
但目前我们还有办法解决,那就是使用短语查询:
GET t1/_doc/_search
{
"query": {
"match_phrase": {
"title": {
"query": "中国"
}
}
}
}
这里match_phrase
是在文档中搜索指定的词组,而中国
则正是一个词组,所以愉快的返回了。
那么,现在我们要想搜索中国和世界相关的文档,但又忘记其余部分了,怎么做呢?用 match 也不行,那就继续用 match_phrase 试试:
GET t1/_doc/_search
{
"query": {
"match_phrase": {
"title": "中国世界"
}
}
}
很明显结果为空,因为没有中国世界
这个短语
我们搜索中国
和世界
这两个指定词组时,但又不清楚两个词组之间有多少别的词间隔。那么在搜的时候就要留有一些余地。这时就要用到了slop了。相当于正则中的中国.*?世界。这个间隔默认为0,导致我们刚才没有搜到,现在我们指定一个间隔
GET t1/_doc/_search
{
"query": {
"match_phrase": {
"title": {
"query": "中国世界",
"slop": 2
}
}
}
}
现在,两个词组之间有了2个词的间隔,这个时候,就可以查询到结果了:
#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.99876255,
"hits" : [
{
"_index" : "t1",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.99876255,
"_source" : {
"title" : "中国是世界上人口最多的国家"
}
}
]
}
}
11.3 match 系列之 match_phrase_prefix(最左前缀查询)
当准备搜索 beautiful girl
词语时。但单词 beautiful
拼到 bea
就不知道往下怎么拼了。这个时候,elasticsearch 就可以看自己的词库有啥 bea
开头的词,结果还真发现了两个:
准备数据
PUT t3/_doc/1
{
"title": "maggie",
"desc": "beautiful girl you are beautiful so"
}
PUT t3/_doc/2
{
"title": "sun and beach",
"desc": "I like basking on the beach"
}
但这里用 match 和 match_phrase 都不太合适,因为输入的不是完整的词。
可以用 match_phrase_prefix 来搞:
GET t3/_doc/_search
{
"query": {
"match_phrase_prefix": {
"desc": "bea"
}
}
}
结果如下
#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.9530774,
"hits" : [
{
"_index" : "t3",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.9530774,
"_source" : {
"title" : "maggie",
"desc" : "beautiful girl you are beautiful so"
}
},
{
"_index" : "t3",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.6931472,
"_source" : {
"title" : "sun and beach",
"desc" : "I like basking on the beach"
}
}
]
}
}
前缀查询是短语查询类似,但前缀查询可以更进一步的搜索词组,只不过它是和词组中最后一个词条进行前缀匹配(如搜这样的 you are bea)。应用也非常的广泛,比如搜索框的提示信息,当使用这种行为进行搜索时,最好通过 max_expansions 来设置最大的前缀扩展数量,因为产生的结果会是一个很大的集合,不加限制的话,影响查询性能。
GET t3/_doc/_search
{
"query": {
"match_phrase_prefix": {
"desc": {
"query": "bea",
"max_expansions": 1
}
}
}
}
结果如下
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "t3",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.6931472,
"_source" : {
"title" : "sun and beach",
"desc" : "I like basking on the beach"
}
}
]
}
}