阅读前须知
本文通过安装elasticsearch-7.17.0为基础,使用 kibana-7.17.0 对 elasticsearch 进行操作,本文中 es 是对 elasticsearch 的简写。
下载地址:elasticsearch_免费高速下载|百度网盘-分享无限制 (baidu.com)
1 初识Elasticsearch
概述:Elasticsearch是一个基于Lucene的搜索引擎,具有分布式特性,能够处理大规模数据的实时搜索和分析。它通过RESTful API提供强大的全文搜索能力,并支持复杂的查询、聚合分析和多种数据格式。Elasticsearch常用于日志分析、数据监控和搜索应用等场景,通常与Kibana和Logstash一起使用,形成ELK栈。
1.1 全文检索
概述:
①、Elasticsearch是一个全文检索服务器,全文检索是一种非结构化数据的搜索方式。
②、结构化数据一般存入数据库,使用sql语句即可快速查询。但由于非结构化数据的数据量大且格式不固定,我们需要采用全文检索的方式进行搜索。全文检索通过建立倒排索引加快搜索效率。
1.2 倒排索引
概述:
①、将数据中的一部分信息提取出来,重新组织成一定的数据结构,我们可以根据该结构进行快速搜索,这样的结构称之为索引。
②、索引即目录,例如字典会将字的拼音提取出来做成目录,通过目录即可快速找到字的位置。
③、索引分为正排索引和倒排索引。
正排索引:将文档 id 建立为索引,通过 id 快速可以快速查找数据。如数据库中的主键就会创建正排索引。
倒排索引:非结构化数据中我们往往会根据关键词查询数据。此时我们将数据中的关键词建立为索引,指向文档数据,这样的索引称为倒排索引。
创建倒排索引的流程:
1.3 ES的数据结构
文档(Document):文档是可被查询的最小数据单元,一个 Document 就是一条数据。类似于关系型数据库中的记录的概念。
类型(Type):具有一组共同字段的文档定义成一个类型,类似于关系型数据库中的数据表的概念。
索引(Index):索引是多种类型文档的集合,类似于关系型数据库中的库的概念。
域(Fied):文档由多个域组成,类似于关系型数据库中的字段的概念。
注:ES7.X之后删除了type的概念,一个索引不会代表一个库,而是代表一张表。
总结: ES中有很多概念与Mysql差不多,ES7及以上版本中,索引相当于Mysql中的表,文档相当于Mysql中的每一条记录(每个文档都有唯一的ID),域相当于Mysql中的每一列,域是文档中的具体数据项。
2 安装Elasticsearch
2.1 安装ES服务
①、准备一台装载有centos7的虚拟机,并能让xshell远程连接该虚拟机:
创建好虚拟机后,首先修改虚拟机的网络配置文件:
vim /etc/sysconfig/network-scripts/ifcfg-ens33
修改的内容如下:
# 修改如下内容
BOOTPROTO="static"
# 增加如下内容
IPADDR=192.168.1.123
NETMASK=255.255.255.0
GATEWAY=192.168.1.9
DNS1=8.8.8.8
接下来配置虚拟网络编辑器:vmware左上角的编辑 > 虚拟网络编辑器
接下来重启虚拟机网络:
systemctl restart network
最后测试网络是否配置成功:
ping baidu.com
运行结果如下:(能ping通就说明配置成功了)
接下来用xshell远程连接虚拟机即可:打开Xshell > 文件 > 新建
连接后结果如下:
②、关闭防火墙,方便访问ES:
# 关闭防火墙
systemctl stop firewalld.service
# 禁止防火墙自启动
systemctl disable firewalld.service
运行结果如下:
③、配置最大可创建文件数大小:
# 打开系统文件
vim /etc/sysctl.conf
# 添加以下配置
vm.max_map_count=655360
# 生效修改的配置文件
sysctl -p
运行结果如下:
④、由于ES不能以root用户运行,需要创建一个非root用户,此处创建一个名为es的用户:
useradd muxikeqi
运行结果如下:
⑤、通过rz命令将linux版的ES上传至虚拟机:
# 切换到根目录
cd /
# 创建一个文件夹用于放置上传的文件
mkdir app
# 进入创建的文件
cd app/
# 通过rz命令上传文件,-be用于解决乱码问题
rz -be
# 选择准备好的es的后缀为.tar.gz压缩包进行上传
运行结果如下:
⑥、解压ES:
# 对上传的压缩包进行解压
tar -zxvf elasticsearch-7.17.0-linux-x86_64.tar.gz
# 对解压后的目录进行重命名
mv elasticsearch-7.17.0 elasticsearch1
# 将重命名后的文件夹移动到/usr/local/目录下
mv elasticsearch1 /usr/local
# 由于es不能用root用户启动,所以要提取为该目录变更权限,后续用muxikeqi用户进行操作
chown -R muxikeqi:muxikeqi /usr/local/elasticsearch1/
运行结果如下:
⑦、启动ES服务:
# 运行前先切换到指定用户
su muxikeqi
# 进入指定目录
cd /usr/local/elasticsearch/
# 前台运行es
./bin/elasticsearch
# 推荐后台运行es
./bin/elasticsearch &
# 启动完成后通过如下命令查看es是否启动成功(原理是es默认占用9200端口)
curl 127.0.0.1:9200
运行结果如下:
2.2 安装ES的可视化工具(Kibana)
概述:Kibana是一款开源的数据分析和可视化平台,设计用于和Elasticsearch协作。我们可以使用Kibana对Elasticsearch索引中的数据进行搜索、查看、交互操作。
注意:Kibana的版本一定要与安装的ES版本一致。
①、上传并解压Kibana压缩包:
# 切换到root用户
su root
# 进入根目录下的app目录中
cd /app/
# 通过rz命令将准备好的kibana压缩文件进行上传
rz -be
# 直接将压缩包的内容解压到/usr/local/目录下
tar -zxvf kibana-7.17.0-linux-x86_64.tar.gz -C /usr/local/
# 切换到/usr/local/目录下
cd /usr/local/
# 对刚刚解压的文件进行重命名
mv kibana-7.17.0-linux-x86_64/ kibana1
运行结果如下:
②、修改kibana的配置文件:
# 编辑kibana配置文件
vim ./kibana1/config/kibana.yaml
# 文件中添加如下内容(注意:冒号后要空格,否则会报错)
server.host: "192.168.1.123"
elasticsearch.hosts: ["http://127.0.0.1:9200"]
运行结果如下:
③、启动kibana:
提示:由于kibana也不能由root用户启动,因此也要改变kibana目录所属用户及其用户组。
# 在root用户下将kibana目录所属用户修改为muxikeqi
chown -R muxikeqi:muxikeqi /usr/local/kibana1/
# 切换到muxikeqi用户
su muxikeqi
# 进入kibana目录
cd /usr/local/kibana1/
# 启动kibana
./bin/kibana
运行结果如下:
④、访问kibana:
概述:在浏览器的地址栏中输入http://虚拟机IP:5601即可访问kibana。
我在浏览器地址中填入的是http://192.168.1.123:5601,出现如下界面即成功:
3 Elasticsearch基操
3.1 索引操作
概述:Elasticsearch是使用RESTful风格的http请求访问操作的,请求参数和返回值都是Json格式的,我们可以使用kibana发送http请求操作ES。
3.1.1 创建没有结构的索引
路径:ip地址:端口号/索引名;
请求方式:PUT;
注意:由于 kibana 已经连接到ES,所以直接指定索引即可。
知识点1:创建索引的语法如下:
PUT /索引名
知识点2:为没有结构的索引添加结构的参考语法如下:(下面是为索引添加结构的参考语法,索引相当于SQL里的表,域名相当于SQL里的列,_mapping 和 "properties" 是为索引添加结构的固定语法。)
PUT /索引名/_mapping
{
"properties":{
"域名1":{
"type":域的类型,
"store":是否存储,
"index":是否创建索引,
"analyzer":分词器
},
"域名2":{
...
}
}
}
实操1:演示如何通过 kibana 创建一个名为 student 且没有结构的索引。
首先在浏览器地址栏输入 http://虚拟机主机IP:5601,然后按下图所示步骤进行操作:
进入如下页面:
情况代码替换成如下代码:
PUT /student
参考图片如下:
运行完成后按下图步骤操作查看当前的索引:
进入新页面后按下图点击即可查看当前的索引:
运行结构如下:
实操2:演示如何为索引添加结构。
直接进入 kibana 的 Dev Tools 进行编码并运行,编码如下:
PUT /student/_mapping
{
"properties":{
"id":{
"type":"integer"
},
"name":{
"type":"text"
},
"age":{
"type":"integer"
}
}
}
参考截图如下:
运行结果如下:
接下来通过 kibana 的 Static Management 来查看索引结构:
结构如下:
3.1.1 创建有结构的索引
概述:在上一小节中创建了没有结构的索引,并通过 _mapping 为索引添加了结构,本章节将演示如何直接创建有结构的索引(语法上基本一样)
知识点1:下面是直接创建有结构索引的参考语法:
PUT /索引名
{
"mappings":{
"properties":{
"域名1":{
"type":域的类型,
"store":是否存储,
"index":是否创建索引,
"analyzer":分词器
},
"域名2":{
...
}
}
}
}
知识点2:删除索引的参考语法如下:
DELETE /索引名
实操3:通过 kibana 创建一个名为 student001 的有结构索引。(实操1和实操2中已详细展示了如何进入 kibana 的编辑页面,如何查看结构,所以后面的实操中将不演示)
PUT /student001
{
"mappings": {
"properties": {
"id":{
"type": "integer"
},
"name":{
"type": "text"
},
"age":{
"type": "integer"
}
}
}
}
运行结果如下:
实操4:删除es中名为student的索引。
DELETE /student
运行结果如下:
3.2 文档操作
概述:文档操作就是对每条数据进行操作。
3.2.1 增删改查数据
知识点1:下面是新增/修改文档的参考语法:
# 在索引中添加文档
POST /索引名/_doc/[_id值]
{
# 在文档中指定对应的域(域就是文档中具体的值,允许有多条)
"域名":域的值
}
注意:中括号中的 _id 值表示可省略,_id 值不写时自动生成文档 _id ,当设置的 _id 和已有 _id 重复时修改文档。
知识点2:下面是通过 _id 进行查询的参考语法:
GET /索引/_doc/_id值
知识点3:下面是删除文档的参考语法:
DELETE /索引/_doc/_id值
实操5:利用 kibana 创建一个名为 student 的索引,并为该索引添加几条数据,添加完成后查询新增的文档,然后尝试删除新增的文档。
POST /student/_doc/
{
"name":"zs",
"id":1,
"age":22
}
运行结果如下:
从结构中不难发现,即使创建文档时没有指定 _id ,创建时也会自动生成一个 _id 。
接下来尝试查询新增的文档:
GET /student/_doc/ocs1SJIBQG0lZjeULPJE
运行结构如下:
最后尝试删除创建的文档然后再对该文档进行查询:
DELETE /student/_doc/ocs1SJIBQG0lZjeULPJE
运行结果如下:
再次查询删除掉的文档:
GET /student/_doc/ocs1SJIBQG0lZjeULPJE
运行结果如下:
3.2.2 批量操作和修改部分字段
知识点1:根据ID批量查询文档的参考语法如下:
GET /索引/_mget
{
"docs":[
{"_id":_id值},
{"_id":_id值}
]
}
知识点2:查询所有文档的参考语法如下:
GET /索引/_search
{
"query": {
"match_all": {}
}
}
知识点3:修改文档部分域的语法如下:
POST /索引/_doc/_id值/_update
{
"doc":{
域名:值
}
}
实操6:为student索引中添加多条文档,然后尝试查询所有文档和修改文档部分字段的操作。
首先为索引添加多条文档:
POST /student/_doc/1
{
"name":"zs",
"age":20,
"city":"cs"
}
POST /student/_doc/2
{
"name":"ls",
"age":21,
"city":"bj"
}
POST /student/_doc/3
{
"name":"ww",
"age":22,
"city":"gz"
}
运行结果如下:
接下来利用ID做批量查询的操作:
# 注意:最后一个大括号后面不要加逗号,否则会报错
GET /student/_mget
{
"docs":[
{"_id":1},
{"_id":2},
{"_id":3}
]
}
运行结果如下:
接下来通过 _search 实现查询所有文档:
GET /student/_search
{
"query": {
"match_all": {}
}
}
运行结果如下:
现突然发现 _id 为 3 的文档 city 值应该为 sc ,尝试修改该文档的 city 字段值:
POST /student/_doc/3/_update
{
"doc":{
"city":"sc"
}
}
运行结果如下:
最后尝试单独查询 _id 为3的文档内容:
GET /student/_doc/3
运行结果如下:
注意事项:
①、Elasticsearch执行删除操作时,ES先标记文档为deleted状态,而不是直接物理删除。当ES存储空间不足或工作空闲时,才会执行物理删除操作。
②、Elasticsearch执行修改操作时,ES不会真的修改Document中的数据,而是标记ES中原有的文档为deleted状态,再创建一个新的文档来存储数据。
3.3 域的属性
3.3.1 index
概述:index 用于指定该域是否创建倒排索引,当 index 的值设置为 true 时才能根据该域的关键词查询文档。
知识点1:根据关键词查询文档的参考语法如下:
GET /索引名/_search
{
"query":{
"term":{
搜索字段: 关键字
}
}
}
实操7:分别创建两个索引,一个指定创建倒排索引,另一个不创建倒排索引,然后分别测试是否支持根据关键字进行查询。
首先创建两个索引:
PUT /student2
{
"mappings":{
"properties":{
"name":{
"type":"text",
"index": true
}
}
}
}
PUT /student3
{
"mappings": {
"properties": {
"name":{
"type": "text"
, "index": false
}
}
}
}
运行结果如下:
接下来为两个新创建的索引插入数据:
POST /student2/_doc
{
"name":"i like study spider"
}
POST /student3/_doc
{
"name":"i like study spider"
}
运行结果如下:
接下来尝试根据关键词查询student2文档:
GET /student2/_search
{
"query": {
"term": {
"name": "spider"
}
}
}
运行结果如下:
最后尝试根据关键词查询student3文档:
GET /student3/_search
{
"query": {
"term": {
"name": "spider"
}
}
}
运行结果如下:
总结:从本案例可以发现当文档创建了倒排索引就支持根据关键词进行查询,反之就不支持。
3.3.2 type
域的类型 :
核心类型 具体类型 字符串类型 text 整数类型 long, integer, short, byte 浮点类型 double, float 日期类型 date 布尔类型 boolean 数组类型 array 对象类型 object 不分词的字符串 keyword
实操8:创建一个名为student4的索引,该索引包含一个字段即可,类型设置为keyword,并且设置倒排索引,测试该情况下是否能根据关键词进行查询。
首先创建student4的索引及其结构:
PUT /student4
{
"mappings": {
"properties": {
"names":{
"type": "keyword",
"index": true
}
}
}
}
运行结果如下:
接下来为创建好的文档添加数据:
POST /student4/_doc
{
"names":"i like study spider"
}
运行结果如下:
最后尝试做关键词查询:
GET /student4/_search
{
"query": {
"term": {
"names": "spider"
}
}
}
运行结果如下:
注意:虽然并没有报错,但没有查询到拥有关键词的数据,原因就是keyword类型的字段不会根据空格做分词,names的整个值就是一整个词,所以拿其中的一部分是无法查询到的。
最后尝试用整个值去做查询:
GET /student4/_search
{
"query": {
"term": {
"names": "i like study spider"
}
}
}
运行结果如下:
总结:当文档的类型设置为 keyword 时,用关键词对其做查询是查询不到数据的,因为 keyword 类型不会根据空格做分词,该类型一般用于手机号,身份证号等不适于分词的场景。
3.3.3 store
概述:store表示是否单独存储。如果设置为true,则该域能够单独查询。
知识点1:下面是单独查询某个域的参考语法:
GET /索引名/_search
{
"stored_fields": ["域名"]
}
实操9:分别尝试对设置了store和没有设置store的文档做单独匹配。
首先创建两个索引及其结构:
PUT /student5
{
"mappings": {
"properties": {
"age":{
"type": "integer"
},
"name":{
"type": "text",
"index": true,
"store": true
}
}
}
}
PUT /student6
{
"mappings": {
"properties": {
"age":{
"type": "integer"
},
"name":{
"type": "text",
"index": true,
"store": false
}
}
}
}
运行结果如下:
然后为两个索引添加对应的域:
POST /student5/_doc
{
"age":18,
"name":"i'm scrapy for baidu"
}
POST /student6/_doc
{
"age":20,
"name":"i'm scrapy for google"
}
运行结果如下:
接下来对设置了 store 的 student5 索引做单独查询:
GET /student5/_search
{
"stored_fields": ["name"]
}
运行结果如下:
最后对没有设置 store 的 student6 索引做域的单独查询:
GET /student6/_search
{
"stored_fields": ["name"]
}
运行结果如下:
总结:如果所有的文档中设置了 store 将支持域的单独查询,如果对没有设置 store 的文档做域的单独查询虽然不会报错,但无法查询到域的数据,本设置一般用于经常需要查询的域。
4 分词器
概述:ES文档的数据拆分成一个个有完整含义的关键词,并将关键词与文档对应,这样就可以通过关键词查询文档。要想正确的分词,需要选择合适的分词器。
4.1 默认分词器
概述 :Elasticsearch 默认分词器 (standard analyzer) 会根据空格和标点符号对英文进行分词,会进行单词的大小写转换。
注意:默认分词器是英文分词器,对中文的分词是一字一词。
知识点:查看分词效果的参考语法如下:
GET /_analyze
{
"text":测试语句,
"analyzer":分词器
}
实操10:尝试查看默认分词器的效果:
GET /_analyze
{
"text": ["crawl by scrapy"],
"analyzer": "standard"
}
运行结果如下:
下面尝试利用默认分词器对中文进行分词:
GET /_analyze
{
"text": ["爬虫"],
"analyzer": "standard"
}
运行结果如下:
4.2 IK分词器
4.2.1 IK分词器的安装
概述:IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。提供了两种分词算法:
-
ik_smart:最少切分
-
ik_max_word:最细粒度划分
实操11:安装IK分词器:
①、关闭ES:
# 暂停正在运行的es
Ctrl + z
# 切换到root用户
su
# 查看es的相关进程
ps -ef | grep elasticsearch
# 根据上一步获取的进程号强行杀死该进程
kill -9 获取的进程号1 获取的进程号2 ...
运行结果如下:
②、通过 rz 命令将 IK 分词器上传到虚拟机:(IK分词器的版本要与ES的版本一致)
# 进入上传文件的暂存目录/app
cd /app/
# 通过rz命令上传文件
rz -be
运行结果如下:
③、将压缩文件解压到ES目录下plugins目录中:
unzip elasticsearch-analysis-ik-7.17.0.zip -d /usr/local/elasticsearch1/plugins/analysis-ik
运行结果如下:
④、启动ES和Kibana:
# 切换到其它用户
su muxikeqi
# 进入es和kibana所在目录
cd /usr/local/
# 后台运行es
./elasticsearch1/bin/elasticsearch -d
# 运行kibana
./kibana1/bin/kibana
运行结果如下:
⑤、进入Kibana测试IK分词器:
首先尝试 ik_smart 进行分词:
GET /_analyze
{
"text": ["今天天气真不错"],
"analyzer": "ik_smart"
}
运行结果如下:
接下来尝试用 ik_max_word 进行分词:
GET /_analyze
{
"text": ["今天天气真不错"],
"analyzer": "ik_max_word"
}
运行结果如下:
4.2.2 IK分词器词典
概述:IK分词器根据词典进行分词,词典文件在IK分词器的config目录中:
-
main.dic:IK中内置的词典。记录了IK统计的所有中文单词。
-
IKAnalyzer.cfg.xml:用于配置自定义词库。
实操12:由于 IK 分词器并不会囊括所有的词语,所以可以通过修改 IKanalyzer.cfg.xml 文件实现自定义词库,本实操主要讲解如何操作自定义词库。
首先看一下 IK分词器 内置的词典包括多少字词:
# 进入IK分词器所在路径
cd /usr/local/elasticsearch1/plugins/analysis-ik/config/
# 通过cw命令查看main.dic文件有多少行,每一行就是一个字/词
wc -l main.dic
运行结果如下:
接下来尝试设置一个自定义词库,首先编辑 IKAnalyzer.cfg.xml 文件:
# 编辑自定义词库的配置文件
vim ./IKAnalyzer.cfg.xml
# 完整文件内容如下,主要是设置了扩展字典和停止词字典
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">ext_word.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">ext_stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
# 创建并编辑ext_word.dic (扩展字典)
vim ext_word.dic
# 创建并编辑ext_stopword.dic (停用字典:就是遇到停用词典里的词后将不会分词)
vim ext_stopword.dic
参考代码如下:
修改完成后需要重启 ES 和 kibana :
# 过滤elastic相关的端口号
ps -ef | grep elastic
# 通过上面获取的端口号强行杀死进程
kill -9 端口1 端口2 ...
参考截图如下:
然后启用ES和kibana即可:
# 切换到其它用户
su muxikeqi
# 进入es与kibana所在目录
cd /usr/local/
# 后台启动es
./elasticsearch1/bin/elasticsearch -d
# 启动kibana
./kibana1/bin/kibana
参考截图如下:
进入kibana测试是否能使用自定义的词典:
GET /_analyze
{
"text": ["小孩哥小孩姐"],
"analyzer": "ik_max_word"
}
运行结果如下:
4.3 拼音分词器
概述:拼音分词器可以将中文分成对应的全拼,全拼首字母等。
实操13:安装并测试拼音分词器:
①、关闭ES服务:
# 获取elastic相关的进程号
ps -ef | grep elastic
# 强制杀掉相关的进程号
kill -9 进程号1 进程号2 ...
参考截图如下:
②、利用rz命令将拼音分词器上传至虚拟机并解压:(版本需与ES一致)
# 进入暂存目录
cd /app
# 通过rz命令上传压缩包
rz -be
# 将上传的压缩包解压到es目录下的plugins目录中
unzip elasticsearch-analysis-pinyin-7.17.0.zip -d /usr/local/elasticsearch1/plugins/analysis-pinyin
运行结果如下:
③、启动ES和kibana:
# 切换到其它用户
su muxikeqi
# 进入es和kibana所在的目录
cd /usr/local/
# 后台启动es
./elasticsearch1/bin/elasticsearch -d
# 启动kibana
./kibana1/bin/kibana
运行结果如下:
④、测试效果:
进入kibana测试如下代码:
GET /_analyze
{
"text": ["小孩哥"],
"analyzer": "pinyin"
}
运行结果如下:
4.4 自定义分词器
概述:真实开发中我们往往需要对一段内容既进行文字分词,又进行拼音分词,此时我们需要自定义ik+pinyin分词器。
知识点:在创建索引时自定义分词器的参考代码如下:
PUT /索引名
{
"settings" : {
"analysis" : {
"analyzer" : {
"自定义分词器名" : {
"tokenizer":"ik_max_word", // 基本分词器
"filter":"pinyin_filter" // 配置分词器过滤
}
},
"filter" : { // 分词器过滤时配置另一个分词器,相当于同时使用两个分词器
"pinyin_filter" : {
"type" : "pinyin", // 另一个分词器
// 拼音分词器的配置
"keep_separate_first_letter" : false, // 是否分词每个字的首字母
"keep_full_pinyin" : true, // 是否分词全拼
"keep_original" : true, // 是否保留原始输入
"remove_duplicated_term" : true // 是否删除重复项
}
}
}
},
"mappings":{
"properties":{
"域名1":{
"type":域的类型,
"store":是否单独存储,
"index":是否创建倒排索引,
"analyzer":选择自定义的分词器
},
"域名2":{
...
}
}
}
}
实操14:创建一个自定义分词器并进行测试。
首先创建一个拥有自定义分词器的索引:
PUT /student7
{
"settings": {
"analysis": {
"analyzer": {
"ik_pinyin":{
"tokenizer":"ik_max_word",
"filter":"pinyin_filter"
}
},
"filter": {
"pinyin_filter":{
"type":"pinyin",
"keep_separate_first_letter" : false,
"keep_full_pinyin" : true,
"keep_original" : true,
"remove_duplicated_term" : true
}
}
}
},
"mappings":{
"properties":{
"name":{
"type":"text",
"store":true,
"index":true,
"analyzer":"ik_pinyin"
},
"age":{
"type": "integer"
}
}
}
}
运行结果如下:
注意:由于自定义分词器绑定到指定索引,所以测试时要指定对哪个索引进行测试:
GET /student7/_analyze
{
"text": ["小孩哥小孩姐"],
"analyzer": "ik_pinyin"
}
运行结果如下:
5 ES搜索文档
5.1 前期准备工作
概述:为了本章节能更好的运用已学知识和测试命令效果,所以提前在本章节创建索引,并向索引中添加多个文档。
知识点:文档搜索的语法如下:
GET /索引/_search
{
"query":{
搜索方式:搜索参数
}
}
实操15:准备文档搜索章节的测试索引及其文档:
创建索引:
PUT /students
{
"mappings":{
"properties":{
"id": {
"type": "integer",
"index": true
},
"name": {
"type": "text",
"store": true,
"index": true,
"analyzer": "ik_smart"
},
"info": {
"type": "text",
"store": true,
"index": true,
"analyzer": "ik_smart"
}
}
}
}
运行结果如下:
添加文档:
POST /students/_doc/
{
"id":1,
"name":"niko",
"info":"世界第一步枪手"
}
POST /students/_doc/
{
"id":2,
"name":"donk",
"info":"cs2的新生代突破手"
}
POST /students/_doc/
{
"id":3,
"name":"zywoo",
"info":"牢底坐穿王"
}
POST /students/_doc/
{
"id":4,
"name":"tyloo",
"info":"未来可期,先荣为敬"
}
POST /students/_doc/
{
"id":5,
"name":"jks",
"info":"廉颇老矣,尚能饭否"
}
POST /students/_doc/
{
"id":6,
"name":"总监",
"info":"发型越飘逸,战力越难测"
}
运行结果如下:
5.2 搜索方式
5.2.1 match & match_all
知识点1:match_all 用于查询所有文档,参考语法如下:
{
"query":{
"match_all":{}
}
}
知识点2:match 用于全文检索,将查询条件分词后再进行搜索,参考语法如下:
{
"query":{
"match":{
搜索字段:搜索条件
}
}
}
知识点3:在搜索时关键词有可能会输入错误,ES搜索提供了自动纠错功能,即ES的模糊查询。使用match方式可以实现模糊查询。模糊查询对中文的支持效果一般,我们使用英文数据测试模糊查询,参考语法如下:
{
"query": {
"match": {
"域名": {
"query": 搜索条件,
"fuzziness": 最多错误字符数,不能超过2
}
}
}
}
实操16:查询students索引中所有的文档:
GET /students/_search
{
"query": {
"match_all": {}
}
}
运行结果如下:
实操17:查询students索引中info对应的内容中包含关键词 "世界" 的域:
GET /students/_search
{
"query": {
"match": {
"info": "世界"
}
}
}
运行结果如下:
实操18:演示 match 如何通过一句话做关联查询:(先对整句话做分词,然后再对指定的域做匹配)
GET /students/_search
{
"query": {
"match": {
"info": "世界最顶级的cs比赛"
}
}
}
运行结果如下:
实操19:测试 match 方法的纠错功能:(最多支持两个字母纠错,以下情况都算一个字母的纠错:多一个字母,少一个字母,两个字母的位置放反了)
GET /students/_search
{
"query": {
"match": {
"name": {
"query": "tyl",
"fuzziness": 2
}
}
}
}
运行结果如下:
5.2.2 range & match_phrase & term/terms
知识点1:range用于对数字类型的字段进行范围搜索,参考代码如下:
{
"query":{
"range":{
搜索字段:{
"gte":最小值,
"lte":最大值
}
}
}
}
# gt/lt:大于/小于
# gte/lte:大于等于/小于等于
知识点2:match_phrase 用于短语检索。搜索条件不做任何分词解析,在搜索字段对应的倒排索引中精确匹配,参考语法如下:
{
"query":{
"match_phrase":{
搜索字段:搜索条件
}
}
}
注意:match 方法会对提供的关键词进行分词,然后针对分词后的单个字或词做检索,但match_phrase 不会做分词处理,它会根据提供的关键词直接去做检索。
知识点3:term/terms 用于单词/词组搜索,搜索条件不做任何分词解析,在搜索字段对应的倒排索引中精确匹配 (效果和 match_phrase 相差不大),参考语法如下:
{
"query":{
"term":{
搜索字段: 搜索条件
}
}
}
{
"query":{
"terms":{
搜索字段: [搜索条件1,搜索条件2]
}
}
}
注意:term 与 terms 的区别就是 term 只能跟一个搜索条件,而 terms 能跟多个搜索条件。
实操20:查询students索引中 id 字段的值为 3~4 的数据。
GET /students/_search
{
"query": {
"range": {
"id": {
"gte": 3,
"lte": 4
}
}
}
}
运行结果如下:
实操21:查询各域中info字段中有关 cs2 的数据。
GET /students/_search
{
"query": {
"match_phrase": {
"info": "cs2"
}
}
}
运行结果如下:
5.3 复合搜索
知识点:复合搜索的参考语法如下:
GET /索引/_search
{
"query": {
"bool": { // 复合搜索通过bool关键字实现
// 必须满足的条件
"must": [
搜索方式:搜索参数,
搜索方式:搜索参数
],
// 多个条件有任意一个满足即可
"should": [
搜索方式:搜索参数,
搜索方式:搜索参数
],
// 必须不满足的条件
"must_not":[
搜索方式:搜索参数,
搜索方式:搜索参数
]
}
}
}
注意:复合搜索并不是要同时实现 must , should 和 must_not,任意选择一个实现即可,当然同时选择这三个选项也是可以的。
实操22:实现复合搜索。
GET /students/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"info": "世界最顶级的cs比赛"
}
},{
"range": {
"id": {
"gte": 2
}
}
}
]
}
}
}
运行结果如下:
5.4 结果排序
概述:ES中默认使用相关度分数实现排序,可以通过搜索语法定制化排序,参考语法如下:
GET /索引/_search
{
"query": 搜索条件,
"sort": [
{
"字段1":{
"order":"asc"
}
},
{
"字段2":{
"order":"desc"
}
}
]
}
注意:由于ES对text类型字段数据会做分词处理,使用哪一个单词做排序都是不合理的,所以 ES中默认不允许对text类型的字段做排序。如果需要使用字符串做结果排序,可以使用 keyword类型的字段作为排序依据,因为keyword字段不做分词处理。
实操23:尝试对 id 字段做结果排序:
GET /students/_search
{
"query": {
"match": {
"info": "世界最顶级的cs比赛"
}
},
"sort": [
{
"id": {
"order": "asc"
}
}
]
}
运行结果如下:
5.5 分页查询
知识点:分页查询的参考语法如下:
GET /索引/_search
{
"query": 搜索条件,
"from": 起始下标,
"size": 查询记录数
}
实操24:尝试对查询结果做分页处理。
GET /students/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 2
}
运行结果如下:
5.6 高亮查询
概述:在进行关键字搜索时,搜索出的内容中的关键字会显示不同的颜色,称之为高亮。
知识点:我们可以在关键字左右加入标签字符串,数据传入前端即可完成高亮显示,ES可以对查询出的内容中关键字部分进行标签和样式的设置,参考语法如下:
GET /索引/_search
{
"query":搜索条件,
"highlight":{
"fields": {
"高亮显示的字段名": {
// 返回高亮数据的最大长度
"fragment_size":100,
// 返回结果最多可以包含几段不连续的文字
"number_of_fragments":5
}
},
"pre_tags":["前缀"],
"post_tags":["后缀"]
}
}
实操25:尝试实现高亮查询:
GET /students/_search
{
"query": {
"match": {
"info": "世界最顶级的cs比赛"
}
},
"highlight": {
"fields": {
"info": {
"fragment_size": 20,
"number_of_fragments": 5
}
},
"pre_tags": ["<em>"],
"post_tags": ["</em>"]
}
}
运行结果如下:
5.7 SQL查询
知识点:在ES7之后,支持SQL语句查询文档 (不完全支持所有SQL语句),参考语法如下:
GET /_sql?format=txt
{
"query": SQL语句
}
实操26:尝试利用 sql 语句查询 students 索引中所有的数据:
GET /_sql?format=txt
{
"query": """
SELECT * FROM "students"
"""
}
运行结果如下: