前言:

我们的应用经常需要添加检索功能,更或者是大量日志检索分析等,SpringBoot 通过整合 SpringData Elasticdearch 为我们提供了非常便捷的检索功能支持。

Elasticsearch是一个分布式搜索服务,提供Restful API,底层基于Lucene,采用多Shard的方式保证数据安全,并且提供自动Resharding的功能,GitHub等大型的站点也是采用了 Elasticsearch 作为其搜索服务。

Elasticsearch - 参考文档

Elasticsearch Java REST Client - 参考文档

Spring Data Elasticsearch - 参考文档

搭配项目仓库 Web IDE 观看体验更佳

特别鸣谢:遇见狂神说

一、概述

1.1 与关系型数据库的客观对比

Elasticsearch 是面向文档的,使用 JSON 作为文档的序列化格式。

Elasticsearch(集群)中可以包含多个索引(数据库),每个索引中可以包含多个类型(表),每个类型下又包含多个文档(行),每个文档中又包含多个字段(列)。

与关系型数据库的客观对比如下:

Relational DB Elasticsearch
数据库(database) 索引(indices)
表(tables) 类型(types)(将被弃用)
行(row) 文档(documents)
列(columns) 字段(fields)

1.2 物理设计

Elasticsearch 在后台把每个索引划分为多个分片,每个分片可以在集群中的不同服务器间迁移。

一个运行中的 Elasticsearch 实例称为一个节点,而集群是由一个或者多个拥有相同 cluster.name 配置的节点组成, 它们共同承担数据和负载的压力。

1.3 逻辑设计

一个索引类型中,包含多个文档,比如说文档1、文档2。当索引一篇文档时,可以通过这样的一个顺序找到它:

索引 》类型 》文档id

通过这个组合就能索引到某个具体的文档。(注意id不必是整数,实际上它是个字符串)

  1. 文档

    在 Elasticsearch 中,文档是索引和搜索数据的最小单位。

    文档有几个重要属性:

    • 自我包含:一个文档同时包含字段和对应的值,也就是同时包含 key:value 。
    • 层次性:一个文档中包含自文档。
    • 结构灵活:文档不依赖预先定义的模式。

    尽管可以随意新增或忽略某个字段,但是每个字段的类型非常重要。

  2. 类型

    类型是文档的逻辑容器,就像关系型数据库一样,表格是行的容器。

    类型中对于字段的定义称为映射。

  3. 索引

    索引是映射类型的容器,Elasticsearch 中的索引是一个非常大的文档集合。

    索引存储了映射类型的字段和其它设置,然后它们被存储到了各个分片上。

1.4 工作原理

一个集群至少有一个节点,而一个节点就是一个 Elasticsearch 进程,节点可以有多个默认索引,如果创建索引,那么索引将会有5个分片(primary shard 又称主分片)构成的,每一个主分片会有一个副本(replica shard 又称复制分片)。


上图是一个有3个节点的集群,主分片与对应的复制分片都不回在同一个节点内,这样有利于如果某个节点宕机,数据也不至于丢失。

实际上,一个分片就是一个 Lucene 索引,一个包含倒排索引的文件目录,倒排索引的结构使得 Elasticsearch 在不扫描全部文档的情况下,就能检索文档包含的特定关键字。

1.5 倒排索引

Elasticsearch 使用的是一种称为倒排索引的结构,采用 Lucene 倒排索引作为底层。

这种结构适用于快速的全文搜索,一个索引由文档中所有不重复的列表构成,对于每一个词,都有一个包含它的文档列表。

例如,现在有两个文档,每个文档包含如下内容:

# 文档1包含的内容
Study every day, good good up to forever# 文档2包含的内容
To forever, study every day, good good up

为了创建倒排索引,首先要将每个文档拆分成独立的词(或称为词条或者tokens),然后创建一个包含所有不重复的词条的排序列表,然后列出每个词条出现在哪个文档。

term doc_1 doc_2
Study
To
every
forever
day
study
good
every
to
up

如果搜索 to forever,只需查看包含每个词条的文档。

term doc_1 doc_2
to
forever
total 2 1

两个文档都匹配,但是第一个文档比第二个文档的匹配程度更高。

如果没有别的条件,这两个包含关键字的文档都将返回。

二、部署&测试

2.1 部署 Elasticsearch

  1. 拉取镜像

    docker pull elasticsearch
    
  2. 创建容器

    其中9200是http访问端口,9300是tcp访问端口。

    docker run -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -d -p 9200:9200 -p 9300:9300 --name es elasticsearch:7.6.2
    

    启动异常:

    ERROR: [1] bootstrap checks failed[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least
    

    解决:

    查看max_map_count:

    cat /proc/sys/vm/max_map_count
    65530
    

    设置max_map_count:

    sysctl -w vm.max_map_count=262144
    
  3. 测试

    访问 http://Server-IP:9200 出现以下页面

2.2 部署可视化工具 Elasticsearch-head

  1. 拉取镜像

    docker pull mobz/elasticsearch-head:5
    
  2. 创建容器

    docker run -d -p 9100:9100 --name head mobz/elasticsearch-head:5
    
  3. 解决跨域请求问题

    进入 Elasticsearch 容器,修改配置文件elasticsearch.yml
    行末添加以下字段:

    http.cors.enabled: true
    http.cors.allow-origin: "*"
    

    重启服务

  4. 在查看或操作索引数据时,可能还报如下错误:

    {“error”:“Content-Type header [application/x-www-form-urlencoded] is not supported”,“status”:406}

    解决方法:

    • 进入head 容器

    • 安装 vim

    配置国内镜像源:

    mv /etc/apt/sources.list /etc/apt/sources.list.bakecho "deb http://mirrors.163.com/debian/ jessie main non-free contrib" >> /etc/apt/sources.listecho "deb http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.listecho "deb-src http://mirrors.163.com/debian/ jessie main non-free contrib" >>/etc/apt/sources.listecho "deb-src http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list
    

    更新安装源

    apt-get update
    

    安装 vim

    apt-get install vim
    

    • 进入_site目录,修改vendor.js文件

     ① 6886行 contentType: "application/x-www-form-urlencoded"改成:contentType: "application/json;charset=UTF-8"② 7573行 var inspectData = s.contentType === "application/x-www-form-urlencoded" &&改成:var inspectData = s.contentType === "application/json;charset=UTF-8" &&
    
  5. 测试

    访问 http://Server-IP:9200 出现以下页面

2.3 部署可视化工具 Kibana

  1. 拉取镜像

    docker pull kibana:7.6.2
    
  2. 创建容器

    docker run -d -e ELASTICSEARCH_URL=http://39.105.80.221:9200 -p 5601:5601 --name kibana kibana:7.6.2
    
  3. 修改访问地址&汉化

    进入容器

    修改访问地址:编辑 kibana.yml 将 elasticsearch.hosts 修改为 Elasticsearch 服务地址

    汉化:编辑 kibana.yml 行末添加 i18n.locale: “zh-CN”

  4. 测试

    访问 http://Server-IP:5601 出现以下页面

2.4 安装 IK 分词器

什么是 IK 分词器?

分词:即把一段中文或者英文或分成一个个的关键字,我们在搜索的时候会把输入的信息进行分词,会把数据库或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每一个字看成一个词,但这是不符合实际需求的,所以需要安装中文分词器 IK 来解决这个问题。

IK 提供了两个分词算法:ik_smart 和 ik_max_word ,其中 ik_smart 为最少切片,ik_max_word 为最细粒度切片。

  1. 进入 elasticsearch 容器

  2. 安装 wget

    yum -y install wget
    
  3. 在 plugins 目录下创建 ik 目录

    mkdir ik
    
  4. 进入 ik 目录使用 wget 下载对应版本

    wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.6.2/elasticsearch-analysis-ik-7.6.2.zip
    
  5. 解压压缩包

    unzip elasticsearch-analysis-ik-7.6.2.zip
    
  6. 删除压缩包

    rm -rf elasticsearch-analysis-ik-7.6.2.zip
    
  7. 验证

    重启 elasticsearch 容器后重新进入容器,在 bin 目录下执行指令:

    elasticsearch-plugin list
    

    显示 ik 即表示安装成功

  8. 测试

    在 Kibana Dev Tools 控制台中输入以下命令

    GET _analyze
    {"analyzer": "ik_smart","text": "中国共产党"
    }GET _analyze
    {"analyzer": "ik_max_word","text": "中国共产党"
    }
    

    分别发送请求会得到不同响应

    {"tokens" : [{"token" : "中国共产党","start_offset" : 0,"end_offset" : 5,"type" : "CN_WORD","position" : 0}]
    }
    
    {"tokens" : [{"token" : "中国共产党","start_offset" : 0,"end_offset" : 5,"type" : "CN_WORD","position" : 0},{"token" : "中国","start_offset" : 0,"end_offset" : 2,"type" : "CN_WORD","position" : 1},{"token" : "国共","start_offset" : 1,"end_offset" : 3,"type" : "CN_WORD","position" : 2},{"token" : "共产党","start_offset" : 2,"end_offset" : 5,"type" : "CN_WORD","position" : 3},{"token" : "共产","start_offset" : 2,"end_offset" : 4,"type" : "CN_WORD","position" : 4},{"token" : "党","start_offset" : 4,"end_offset" : 5,"type" : "CN_CHAR","position" : 5}]
    }
    

2.5 添加自定义分词字典

  1. 进入 elasticsearch 容器

  2. 处理中文乱码问题

    编辑 ~/.vimrc 文件,行末添加以下配置:

    set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936
    set termencoding=utf-8
    set encoding=utf-8
    

    保存退出

  3. 进入 IK 插件安装目录

  4. 进入 config 目录

  5. 创建 dic 文件

    touch caixukun.dic
    
  6. 编辑 dic 添加自定义词条

    蔡徐坤
    鸡你太美
    
  7. 编辑 IKAnalyzer.cfg.xml

    <entry key="ext_dict">caixukun.dic</entry>
    
  8. 重启 elasticsearch 容器

  9. 测试

    在 Kibana Dev Tools 控制台中输入以下命令:

    GET _analyze
    {"analyzer": "ik_smart","text": "蔡徐坤鸡你太美"
    }
    

    默认响应数据:

    {"tokens" : [{"token" : "蔡","start_offset" : 0,"end_offset" : 1,"type" : "CN_CHAR","position" : 0},{"token" : "徐","start_offset" : 1,"end_offset" : 2,"type" : "CN_CHAR","position" : 1},{"token" : "坤","start_offset" : 2,"end_offset" : 3,"type" : "CN_CHAR","position" : 2},{"token" : "鸡","start_offset" : 3,"end_offset" : 4,"type" : "CN_CHAR","position" : 3},{"token" : "你","start_offset" : 4,"end_offset" : 5,"type" : "CN_CHAR","position" : 4},{"token" : "太美","start_offset" : 5,"end_offset" : 7,"type" : "CN_WORD","position" : 5}]
    }
    

    自定义字典添加后响应数据:

    {"tokens" : [{"token" : "蔡徐坤","start_offset" : 0,"end_offset" : 3,"type" : "CN_WORD","position" : 0},{"token" : "鸡你太美","start_offset" : 3,"end_offset" : 7,"type" : "CN_WORD","position" : 1}]
    }
    

三、Rest 风格说明

一种软件结构风格,而不是标准,只是提供了一组设计原则和约束条件,它主要用于客户端和服务器交互类的软件。

基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

基本 Rest 命令说明:

method utl地址 描述
PUT localhost:9200/索引名称/类型名称/文档id 创建文档(指定文档id)
POST localhost:9200/索引名称/类型名称 创建文档
POST localhost:9200/索引名称/类型名称/文档id/_update 修改文档
DELETE localhost:9200/索引名称/类型名称/文档id 删除文档
GET localhost:9200/索引名称/类型名称/文档id 通过id查询文档
POST localhost:9200/索引名称/类型名称/_serch 查询所有数据

3.1 基础测试

  1. 在 Kibana Dev Tools 控制台中输入以下命令:

    PUT /test1/type1/1
    {"name": "蔡徐坤","age": 10
    }
    

    • 命令解释:

    PUT:创建命令
    test1:索引
    type1:类型
    1:id
    “name”: “蔡徐坤”:属性
    “age”: 10:属性

  2. 发送请求

    得到响应如下:

    #! Deprecation: [types removal] Specifying types in document index requests is deprecated, use the typeless endpoints instead (/{index}/_doc/{id}, /{index}/_doc, or /{index}/_create/{id}).
    {"_index" : "test1","_type" : "type1","_id" : "1","_version" : 1,"result" : "created","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 0,"_primary_term" : 1
    }
    
  3. 进入 head 查看已创建的索引信息

3.2 创建索引规则

  1. 在 Kibana Dev Tools 控制台中输入以下命令:

    PUT /test2
    {"mappings": {"properties": {"name": {"type": "text"},"age": {"type": "long"},"birthday": {"type": "date"}}}
    }
    
  2. 发送请求

    得到响应如下:

    {"acknowledged" : true,"shards_acknowledged" : true,"index" : "test2"
    }
    
  3. 进入 head 查看已创建的索引信息

3.3 查看默认的信息

如果文档字段没有指定,那么 Elasticsearch 就会自动配置默认字段。

  1. 在 Kibana Dev Tools 控制台中输入以下命令:
PUT /test3/_doc/1
{"name": "蔡徐坤","age": 10,"birthday": "1998-08-02"
}
  1. 发送请求

    得到响应如下:

    {"_index" : "test3","_type" : "_doc","_id" : "1","_version" : 1,"result" : "created","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 0,"_primary_term" : 1
    }
    
  2. 控制台中输入以下命令:

    GET test3
    
  3. 发送请求

    得到响应如下:

    {"test3" : {"aliases" : { },"mappings" : {"properties" : {"age" : {"type" : "long"},"birthday" : {"type" : "date"},"name" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}}}},"settings" : {"index" : {"creation_date" : "1596476421598","number_of_shards" : "1","number_of_replicas" : "1","uuid" : "Rh3Z67EpSPSOUbz1lmgB7g","version" : {"created" : "7060299"},"provided_name" : "test3"}}}
    }
    

3.4 修改操作

通过 POST 命令实现修改操作。

  1. 在 Kibana Dev Tools 控制台中输入以下命令:
POST /test3/_doc/1/_update
{"doc": {"name": "坤坤"}
}
  1. 发送请求

    得到响应如下:

    #! Deprecation: [types removal] Specifying types in document update requests is deprecated, use the endpoint /{index}/_update/{id} instead.
    {"_index" : "test3","_type" : "_doc","_id" : "1","_version" : 2, // 更新次数"result" : "updated","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 1,"_primary_term" : 1
    }
    

    版本号发生变化

3.5 删除操作

通过 DELETE 命令实现删除操作。

  1. 在 Kibana Dev Tools 控制台中输入以下命令:

    DELETE test1
    
  2. 发送请求

    得到响应如下:

    {"acknowledged" : true
    }
    

3.6 拓展命令

通过 GET _cat 命令可以获得当前 Elasticsearch 集群的许多信息。

  1. 查看集群健康值
GET _cat/health
  1. 查看索引具体信息
GET _cat/indices?v

四、关于文档的基本操作

4.1 添加数据 PUT

  1. 在 Kibana Dev Tools 控制台中输入以下命令:

    PUT /stars/user/1
    {"name": "蔡徐坤","age": "22","desc": "鸡你太美","tags": ["唱","跳","rap","篮球"]
    }
    
  2. 发送请求

    得到响应如下:

    {"_index" : "stars","_type" : "user","_id" : "1","_version" : 1,"result" : "created","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 0,"_primary_term" : 1
    }
    
  3. 添加用户2

    PUT /stars/user/2
    {"name": "吴亦凡","age": "29","desc": "大碗宽面","tags": ["加拿大","电鳗","说唱","嘻哈"]
    }
    
  4. 添加用户3

    PUT /stars/user/3
    {"name": "梁非凡","age": "40","desc": "也啦你","tags": ["桌面清理大师","警察","啵嘴"]
    }
    
  5. 进入 head 查看已创建的索引信息

4.2 查询数据 GET

  1. 简单查询
GET stars/user/1
{"_index" : "stars","_type" : "user","_id" : "1","_version" : 1,"_seq_no" : 0,"_primary_term" : 1,"found" : true,"_source" : {"name" : "蔡徐坤","age" : "22","desc" : "鸡你太美","tags" : ["唱","跳","rap","篮球"]}
}
  1. 复杂查询
    包含关键字匹配
GET stars/user/_search?q=name:吴亦凡
  "took" : 64,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 2.313365,"hits" : [{"_index" : "stars","_type" : "user","_id" : "2","_score" : 2.313365, //匹配度"_source" : {"name" : "吴亦凡","age" : "29","desc" : "大碗宽面","tags" : ["加拿大","电鳗","说唱","嘻哈"]}},{"_index" : "stars","_type" : "user","_id" : "3","_score" : 0.4471386,"_source" : {"name" : "梁非凡","age" : "40","desc" : "吔*啦你","tags" : ["桌面清理大师","警察","啵嘴"]}}]}
}

4.3 更新数据 POST

  1. 在 Kibana Dev Tools 控制台中输入以下命令:

    POST /stars/user/1/_update
    {"doc": {"name": "坤坤"}
    }
    
  2. 发送请求

    得到响应如下:

    {"_index" : "stars","_type" : "user","_id" : "1","_version" : 2, // 更新次数"result" : "updated","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 3,"_primary_term" : 1
    }
    

4.4 删除数据 DELETE

五、高级查询操作

5.1 普通查询

  • 请求

    GET stars/user/_search
    {"query": {"match": {"name": "凡" // 关键字}}
    }
    
  • 响应
    {"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.4471386,"hits" : [{"_index" : "stars","_type" : "user","_id" : "2","_score" : 0.4471386,"_source" : {"name" : "吴亦凡","age" : "29","desc" : "大碗宽面","tags" : ["加拿大","电鳗","说唱","嘻哈"]}},{"_index" : "stars","_type" : "user","_id" : "3","_score" : 0.4471386,"_source" : {"name" : "梁非凡","age" : "40","desc" : "吔*啦你","tags" : ["桌面清理大师","警察","啵嘴"]}}]}
    }
    

5.2 查询结果过滤指定字段

  • 请求

    GET stars/user/_search
    {"query": {"match": {"name": "凡"}},"_source": ["name", "desc"] // 过滤字段
    }
    
  • 响应
    {"took" : 2,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.4471386,"hits" : [{"_index" : "stars","_type" : "user","_id" : "2","_score" : 0.4471386,"_source" : {"name" : "吴亦凡","desc" : "大碗宽面"}},{"_index" : "stars","_type" : "user","_id" : "3","_score" : 0.4471386,"_source" : {"name" : "梁非凡","desc" : "吔*啦你"}}]}
    }
    

5.3 查询结果排序

  • 请求

    GET stars/user/_search
    {"query": {"match": {"name": "凡"}},"sort": [{"age.keyword": {"order": "desc" // 降序}}]
    }
    
  • 响应
    {"took" : 1,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : null,"hits" : [{"_index" : "stars","_type" : "user","_id" : "3","_score" : null,"_source" : {"name" : "梁非凡","age" : "40","desc" : "吔*啦你","tags" : ["桌面清理大师","警察","啵嘴"]},"sort" : ["40"]},{"_index" : "stars","_type" : "user","_id" : "2","_score" : null,"_source" : {"name" : "吴亦凡","age" : "29","desc" : "大碗宽面","tags" : ["加拿大","电鳗","说唱","嘻哈"]},"sort" : ["29"]}]}
    }
    

5.4 查询结果分页

  • 请求

    GET stars/user/_search
    {"query": {"match": {"name": "凡"}},"_source": ["name", "desc"],"from": 0, // 开始位置"size": 1 // 返回数据数目
    }
    
  • 响应
    {"took" : 3,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.4471386,"hits" : [{"_index" : "stars","_type" : "user","_id" : "2","_score" : 0.4471386,"_source" : {"name" : "吴亦凡","desc" : "大碗宽面"}}]}
    }
    

5.5 多条件查询

must:相当于关系型数据库 and

  • 请求

    GET stars/user/_search
    {"query": {"bool": {"must": [{"match": {"name": "吴亦凡"}},{"match": {"age": "29"}}]}}
    }
    
  • 响应
    {"took" : 5,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 3.2941942,"hits" : [{"_index" : "stars","_type" : "user","_id" : "2","_score" : 3.2941942,"_source" : {"name" : "吴亦凡","age" : "29","desc" : "大碗宽面","tags" : ["加拿大","电鳗","说唱","嘻哈"]}}]}
    }
    

should:相当于关系型数据库 or

  • 请求

    GET stars/user/_search
    {"query": {"bool": {"should": [{"match": {"name": "吴亦凡"}},{"match": {"age": "29"}}]}}
    }
    
  • 响应
    {"took" : 1,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 3.2941942,"hits" : [{"_index" : "stars","_type" : "user","_id" : "2","_score" : 3.2941942,"_source" : {"name" : "吴亦凡","age" : "29","desc" : "大碗宽面","tags" : ["加拿大","电鳗","说唱","嘻哈"]}},{"_index" : "stars","_type" : "user","_id" : "3","_score" : 0.4471386,"_source" : {"name" : "梁非凡","age" : "40","desc" : "吔*啦你","tags" : ["桌面清理大师","警察","啵嘴"]}}]}
    }
    

must_not:相当于关系型数据库 not

  • 请求

    GET stars/user/_search
    {"query": {"bool": {"must_not": [{"match": {"age": "29"}}]}}
    }
    
  • 响应
    {"took" : 2,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.0,"hits" : [{"_index" : "stars","_type" : "user","_id" : "3","_score" : 0.0,"_source" : {"name" : "梁非凡","age" : "40","desc" : "吔*啦你","tags" : ["桌面清理大师","警察","啵嘴"]}},{"_index" : "stars","_type" : "user","_id" : "1","_score" : 0.0,"_source" : {"name" : "坤坤","age" : "22","desc" : "鸡你太美","tags" : ["唱","跳","rap","篮球"]}}]}
    }
    

5.6 根据过滤条件查询

  • 请求

    GET stars/user/_search
    {"query": {"bool": {"must": [{"match": {"name": "凡"}}],"filter": [{"range": {"age": {"gte": 10, // 大于等于10岁"lte": 30 // 小于等于30岁}}}]}}
    }
    
  • 响应
    {"took" : 1,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 0.4471386,"hits" : [{"_index" : "stars","_type" : "user","_id" : "2","_score" : 0.4471386,"_source" : {"name" : "吴亦凡","age" : "29","desc" : "大碗宽面","tags" : ["加拿大","电鳗","说唱","嘻哈"]}}]}
    }
    

5.7 匹配多个条件查询

  • 请求

    GET stars/user/_search
    {"query": {"match": {"tags": "唱 跳" // 多个条件使用空格隔开}}
    }
    
  • 响应
    {"took" : 1,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 1.7137355,"hits" : [{"_index" : "stars","_type" : "user","_id" : "1","_score" : 1.7137355,"_source" : {"name" : "坤坤","age" : "22","desc" : "鸡你太美","tags" : ["唱","跳","rap","篮球"]}},{"_index" : "stars","_type" : "user","_id" : "2","_score" : 0.4471386,"_source" : {"name" : "吴亦凡","age" : "29","desc" : "大碗宽面","tags" : ["加拿大","电鳗","说唱","嘻哈"]}}]}
    }
    

5.8 精确查询

关于分词:

  • term:直接通过倒排索引指定的词条进行精确查询
  • match:先分析文档,再通过分析的文档进行查询

两个字段类型:

  • text:会被分词器解析
  • keyword:不会被分词器解析

5.9 高亮查询

  • 请求

    GET stars/user/_search
    {"query": {"match": {"name": "吴亦凡"}},"highlight": {"fields": {"name": {}}}
    }
    
  • 响应
    {"took" : 96,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 2.313365,"hits" : [{"_index" : "stars","_type" : "user","_id" : "2","_score" : 2.313365,"_source" : {"name" : "吴亦凡","age" : "29","desc" : "大碗宽面","tags" : ["加拿大","电鳗","说唱","嘻哈"]},"highlight" : {"name" : ["<em>吴</em><em>亦</em><em>凡</em>" // 高亮标签]}},{"_index" : "stars","_type" : "user","_id" : "3","_score" : 0.4471386,"_source" : {"name" : "梁非凡","age" : "40","desc" : "吔*啦你","tags" : ["桌面清理大师","警察","啵嘴"]},"highlight" : {"name" : ["梁非<em>凡</em>"]}}]}
    }
    

5.10 自定义高亮标签

  • 请求
GET stars/user/_search
{"query": {"match": {"name": "吴亦凡"}},"highlight": {"pre_tags": "<p class='key' style='color:red'>","post_tags": "</p>", "fields": {"name": {}}}
}
  • 响应
{"took" : 4,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 2.313365,"hits" : [{"_index" : "stars","_type" : "user","_id" : "2","_score" : 2.313365,"_source" : {"name" : "吴亦凡","age" : "29","desc" : "大碗宽面","tags" : ["加拿大","电鳗","说唱","嘻哈"]},"highlight" : {"name" : ["<p class='key' style='color:red'>吴</p><p class='key' style='color:red'>亦</p><p class='key' style='color:red'>凡</p>"]}},{"_index" : "stars","_type" : "user","_id" : "3","_score" : 0.4471386,"_source" : {"name" : "梁非凡","age" : "40","desc" : "吔*啦你","tags" : ["桌面清理大师","警察","啵嘴"]},"highlight" : {"name" : ["梁非<p class='key' style='color:red'>凡</p>"]}}]}
}

三、SpringBoot 整合 Elasticsearch

3.1 环境搭建

  1. 导入依赖

    注意 Elasticsearch 版本需保持一致。

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    
  2. 编写配置类

    @Configuration
    public class RestClientConfig extends AbstractElasticsearchConfiguration {@Override@Beanpublic RestHighLevelClient elasticsearchClient() {final ClientConfiguration clientConfiguration = ClientConfiguration.builder().connectedTo("39.105.80.221:9200").build();return RestClients.create(clientConfiguration).rest();}}
    

3.2 索引相关操作

  1. 索引的创建

    @SpringBootTest
    class ElasticApplicationTests {@AutowiredRestHighLevelClient elasticsearchClient;/*** 测试索引的创建*/@Testvoid test01() throws IOException {// 创建请求CreateIndexRequest request = new CreateIndexRequest("test_index");// 客户端执行请求CreateIndexResponse response = elasticsearchClient.indices().create(request, RequestOptions.DEFAULT);System.out.println(response);}}
    
  2. 判断索引是否存在
    @SpringBootTest
    class ElasticApplicationTests {@AutowiredRestHighLevelClient elasticsearchClient;/*** 测试判断索引是否存在*/@Testvoid test02() throws IOException {// 创建请求GetIndexRequest request = new GetIndexRequest("test_index");// 客户端执行请求boolean response = elasticsearchClient.indices().exists(request, RequestOptions.DEFAULT);System.out.println(response);}}
    
  3. 索引的删除
@SpringBootTest
class ElasticApplicationTests {@AutowiredRestHighLevelClient elasticsearchClient;/*** 测试索引的删除*/@Testvoid test03() throws IOException {// 创建请求DeleteIndexRequest request = new DeleteIndexRequest("test_index");// 客户端执行请求AcknowledgedResponse response = elasticsearchClient.indices().delete(request, RequestOptions.DEFAULT);System.out.println(response.isAcknowledged());}}

3.3 文档相关操作

  1. 文档的添加
@Test
void test04() throws IOException {// 创建对象User user = new User("testUser", 18);// 创建请求IndexRequest request = new IndexRequest("test_index");// 设置idrequest.id("1");// 设置请求超时时间request.timeout(TimeValue.timeValueSeconds(1));// 将对象转为JSON数据放入请求request.source(objectMapper.writeValueAsString(user), XContentType.JSON);// 客户端发送请求IndexResponse response = elasticsearchClient.index(request, RequestOptions.DEFAULT);System.out.println(response.toString());System.out.println(response.status());
}
  1. 判断文档是否存在
@Test
void test05() throws IOException {// 创建请求GetRequest request = new GetRequest("test_index", "1");// 客户端发送请求boolean response = elasticsearchClient.exists(request, RequestOptions.DEFAULT);System.out.println(response);
}
  1. 文档信息的获取
@Test
void test06() throws IOException {// 创建请求GetRequest request = new GetRequest("test_index", "1");// 客户端发送请求GetResponse response = elasticsearchClient.get(request, RequestOptions.DEFAULT);System.out.println(response.getSourceAsString());
}
  1. 文档信息的更新
@Test
void test07() throws IOException {// 创建对象User user = new User("testUser", 28);// 创建请求UpdateRequest request = new UpdateRequest("test_index", "1");request.doc(objectMapper.writeValueAsString(user), XContentType.JSON);// 客户端发送请求UpdateResponse response = elasticsearchClient.update(request, RequestOptions.DEFAULT);System.out.println(response.status());
}
  1. 文档信息的删除
@Test
void test08() throws IOException {// 创建请求DeleteRequest request = new DeleteRequest("test_index", "1");// 设置请求超时时间request.timeout(TimeValue.timeValueSeconds(1));// 客户端发送请求DeleteResponse response = elasticsearchClient.delete(request, RequestOptions.DEFAULT);System.out.println(response.status());
}
  1. 文档数据的批量插入
@Test
void test09() throws IOException {// 创建请求BulkRequest request = new BulkRequest();// 设置超时时间request.timeout(TimeValue.timeValueSeconds(10));// 创建批量数据ArrayList<User> users = new ArrayList<>();users.add(new User("testUser02", 20));users.add(new User("testUser03", 21));users.add(new User("testUser04", 22));users.add(new User("testUser05", 23));users.add(new User("testUser06", 24));// 将批量数据添加至请求for (int i = 0; i < users.size(); i++) {request.add(new IndexRequest("test_index").id("" + i).source(objectMapper.writeValueAsString(users.get(i)), XContentType.JSON));}// 客户端发送请求BulkResponse responses = elasticsearchClient.bulk(request, RequestOptions.DEFAULT);System.out.println(responses.hasFailures());
}
  1. 文档的查询
@Test
void test10() throws IOException {// 创建请求SearchRequest request = new SearchRequest("test_index");// 设置搜索条件SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();// 创建查询构建器sourceBuilder.query(QueryBuilders.termQuery("name.keyword", "testUser02"));// 设置超时时间sourceBuilder.timeout(TimeValue.timeValueSeconds(60));request.source(sourceBuilder);// 客户端发送请求SearchResponse response = elasticsearchClient.search(request, RequestOptions.DEFAULT);System.out.println(objectMapper.writeValueAsString(response.getHits()));for (SearchHit hit : response.getHits().getHits()) {System.out.println("----------");System.out.println(hit.getSourceAsMap());}
}

四、实战应用 - 京东搜索

4.1 环境搭建

  1. 导入依赖

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
    </dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.13.1</version>
    </dependency>
    
  2. 配置文件
    server:port: 8080
    spring:thymeleaf:cache: false # 关闭 thymeleaf 缓存
    
  3. controller
    @Controller
    public class IndexController {@GetMapping({"/", "/index"})public String index() {return "index";}}
    

4.2 处理爬虫数据

搭配项目仓库 Web IDE 观看体验更佳

SpringBoot 检索篇 - 整合 Elasticsearch7.6.2相关推荐

  1. SpringBoot入门篇--整合mybatis+generator自动生成代码+druid连接池+PageHelper分页插件

    我们这一一篇博客讲的是如何整合Springboot和Mybatis框架,然后使用generator自动生成mapper,pojo等文件.然后再使用阿里巴巴提供的开源连接池druid,这个连接池的好处我 ...

  2. 玩转 SpringBoot 2 之整合定时任务篇

    前言 通过本文你将了解到如何在 SpringBoot 2 中整合定时任务使用教程,具体详细内容如下: SpringBoot 自带定时任务使用教程 SpringBoot 集成 JDK 定时任务使用教程 ...

  3. 【SpringBoot高级篇】SpringBoot集成Elasticsearch搜索引擎

    [SpringBoot高级篇]SpringBoot集成Elasticsearch搜索引擎 1. 什么是Elasticsearch? 2. 安装并运行Elasticsearch 2.1 拉取镜像 2.2 ...

  4. SpringBoot 实战 (九) | 整合 Mybatis

    微信公众号:一个优秀的废人 如有问题或建议,请后台留言,我会尽力解决你的问题. 前言 如题,今天介绍 SpringBoot 与 Mybatis 的整合以及 Mybatis 的使用,本文通过注解的形式实 ...

  5. 第10章尚硅谷SpringBoot检索

    第10章尚硅谷SpringBoot检索 P20.尚硅谷-SpringBoot高级-检索-Elasticsearch简介&安装 P21.尚硅谷-SpringBoot高级-检索-Elasticse ...

  6. 玩转 SpringBoot 2 之整合 JWT 下篇

    前言 在<玩转 SpringBoot 2 之整合 JWT 上篇> 中介绍了关于 JWT 相关概念和JWT 基本使用的操作方式.本文为 SpringBoot 整合 JWT 的下篇,通过解决 ...

  7. 黑马SpringBoot --基础篇

    目录 导读 1.快速上手 1.1SpringBoot入门程序开发 1.1.1基础创建方式--常规 1.1.2手动创建方式--补充 1.1.3基础创建方式--下载 1.1.4基础创建方式--阿里云 1. ...

  8. springboot mybatis easyui 整合的一个小demo

    springboot mybatis easyui 整合的一个小demo 这是最终完成界面 话不多说 开整! 这是项目结构 数据库 表结构和数据库 (有点乱 之前本来是个正经图书表的 = =.) /* ...

  9. 【SpringBoot应用篇】SpringBoot集成j2cache二级缓存框架

    [SpringBoot应用篇]SpringBoot集成j2cache二级缓存框架 j2cache介绍 j2cache入门使用 pom application.yml caffeine.properti ...

  10. 【SpringBoot框架篇】11.Spring Data Jpa实战

    文章目录 1.简介 1.1.JPA 1.2.Spring Data Jpa 1.3.Hibernate 1.4.Jpa.Spring Data Jpa.Hibernate三者之间的关系 2.引入依赖 ...

最新文章

  1. 一文看懂中国MEMS传感器产业链
  2. 比特币现金(BCH)将在2018年占据主导地位
  3. 跳转路径时资源路径加/和不加/的区别
  4. express项目创建
  5. python运动目标检测与跟踪_基于OpenCV的运动目标检测与跟踪
  6. sql点滴41—MyISAM 和 InnoDB 讲解
  7. python获得距离指定(x,y)固定距离的全部坐标点
  8. MyBatis第2天
  9. Jquery操作select选项集合,判断集合中是否存在option
  10. 基于用户的协同过滤推荐算法(整合)
  11. php stack trace,PHP 异常处理
  12. 6950有史以来最经典玩机宝典/软件包/导航
  13. python 小海龟 教案_幼儿园小班健康活动《勇敢的小海龟》教案
  14. Math常用的数学运算(包括取整、取绝对值、保留几位小数等)
  15. (转)War3 地图编辑器脚本接口说明
  16. android应用apn.xml,android之APN
  17. 简单的猜数字小游戏(1 ~ 100)
  18. Java的Random练习~~生成1~n之间的随机数
  19. 轻松bypass360网站卫士WAFSQL注入防护
  20. DIY 空气质量检测表

热门文章

  1. 动词变名词的变化规则_高中英语动词变名词的变化规则
  2. 编程之美读书笔记_1.4 买书问题
  3. 自动化测试框架Selenium的使用——安装Selenium
  4. iphone上安装android系统,如何在iPhone上安装Android操作系统
  5. 2019年年终总结及明年的期望
  6. 使用Python生成ico文件
  7. 计算机找不到ac97前面板怎么办,Win7前面板没有声音的解决方法(声卡设置+前面板插线)...
  8. Iphone快捷指令示例:自动更换墙纸并叠放近期日程在墙纸上
  9. Origin C编程 -- 自定义函数按位解读数据列
  10. ssoj1556土地购买