ElasticSearch6.5.4 学习笔记
一 简介
ElasticSearch 简介
开源的 Elasticsearch (简称 ES)是目前全文搜索引擎的首选。它可以快速地储存、搜索和分析海量数据。
Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎。
Lucene只是一个库,想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中。Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的
Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTful API 来隐藏Lucene的复杂性,从而让全文搜索变得简单。
Solr简介
- Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务器。Solr提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展,并对索引、搜索性能进行了优化
- Solr是基于lucene开发企业级搜索服务器,实际上就是封装了lucene。
- Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的文件,生成索引;也可以通过提出查找请求,并得到返回结果。
1.1 ElasticSearch和Solr对比
ElasticSearch的优缺点
- 优点
- Elasticsearch是分布式的。不需要其他组件,分发是实时的
- Elasticsearch 完全支持 Apache Lucene 的接近实时的搜索
- 处理多租户(multitenancy)不需要特殊配置,而Solr则需要更多的高级设置
- 各节点组成对等的网络结构,某些节点出现故障时会自动分配其他节点代替其进行工作
- 缺点
- 还不够自动,不适合当前新的Index Warmup API (参考:zhaoyanblog.com/archives/76…)
Solr的优缺点
- 优点
- Solr有一个更大、更成熟的用户、开发和贡献者社区。
- 支持添加多种格式的索引,如:HTML、PDF、微软 Office 系列软件格式以及 JSON、XML、CSV 等纯文本格式。
- 不考虑建索引的同时进行搜索,速度更快。即Solr在查询死数据时,速度相对ES更快一些,如果数据是实时变化的,Solr的查询速度会降低很多,ES的查询效率基本没有变化
- 缺点
- Solr 在国内的文档不是很多很全
- Solr搭建集群时需要Zookeeper来管理,ES本身具支持集群的搭建,需不要第三方介入。
1.2 ElasticSearch 使用场景
国外
- 维基百科,类似百度百科,牙膏,牙膏的维基百科,全文检索,高亮,搜索推荐
- The Guardian(国外新闻网站),类似搜狐新闻,用户行为日志(点击,浏览,收藏,评论)+社交网络数据(对某某新闻的相关看法),数据分析,给到每篇新闻文章的作者,让他知道他的文章的公众反馈(好,坏,热门,垃圾,鄙视,崇拜)
- Stack Overflow(国外的程序异常讨论论坛),IT问题,程序的报错,提交上去,有人会跟你讨论和回答,全文检索,搜索相关问题和答案,程序报错了,就会将报错信息粘贴到里面去,搜索有没有对应的答案
- GitHub(开源代码管理),搜索上千亿行代码
- 电商网站,检索商品
- 日志数据分析,logstash采集日志,ES进行复杂的数据分析(ELK技术,elasticsearch+logstash+kibana)
- 商品价格监控网站,用户设定某商品的价格阈值,当低于该阈值的时候,发送通知消息给用户,比如说订阅牙膏的监控,如果高露洁牙膏的家庭套装低于50块钱,就通知我,我就去买
- BI系统,商业智能,Business Intelligence
- 国内:站内搜索(电商,招聘,门户,等等),IT系统搜索(OA,CRM,ERP,等等),数据分析(ES热门的一个使用场景)
1.3 ES总结
- 分布式的搜索引擎和数据分析引擎
- 全文检索,结构化检索,数据分析
- 对海量数据进行近实时的处理
- 文档丰富,国内资料较多
二 ElasticSearch安装(docker环境)
2.1 安装Linux系统(wsl)
网上教程很多,我就在这不赘述了。我使用的是Ubuntu18.04
2.2 安装docker和docker-compose
- 更新系统索引:
sudo apt-get update
- 添加HTTPS协议,允许apt从HTTPS安装软件包:
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
- 添加Docker 公共密钥
# Docker 官方源:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add
#Docker中科大源(国内推荐):
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
-
安装最新版Docker CE
sudo apt-get install docker-ce
-
安装docker-compose(当前最新版本为1.26.2)
sudo curl -L https://github.com/docker/compose/releases/download/1.26.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
- 设置docker-compose权限
sudo chmod +x /usr/local/bin/docker-compose
- 查看docker-compose是否安装成功
docker-compose --version
2.3 安装ElasticSearch 和Kibana
-
使用docker-compose.yml 安装,首先编写docker-compose.yml文件
version: '3.1' services: elasticsearch: image: daocloud.io/library/elasticsearch:6.5.4 restart: always container_name: elasticsearch ports: - 9200:9200 - 9300:9300 kibana: image: daocloud.io/library/kibana:6.5.4 restart: always container_name: kibana ports: - 5601:5601 environment: - elasticsearch_url=http://192.168.75.139:9200 depends_on: - elasticsearch
-
运行:
docker-compose up -d
-
验证ElasticSearch是否启动成功:访问 http://192.168.75.139:9200 (我的IP是192.168.75.139,记住换成自己的哦)
-
验证Kibana是否启动成功:访问http://192.168.75.139:5601
三 Kibana 控制台命令操作ES
3.1 创建索引
#创建索引,指定数据结构
PUT /book
{
"settings": {
# 分片数
"number_of_shards": 5,
# 备份数
"number_of_replicas": 1
},
"mappings": {
# 类型type
"xuanhuan":{
# 文档存储的Filed
"properties":{
# Filed 属性名称
"name":{
"type":"text",
"analyzer":"ik_max_word",
# 指定当前Filed可以作为查询条件
"index":true,
# 是否需要额外存储(一般不需要)
"store":false
},
"author":{
"type":"keyword"
},
"count":{
"type":"long"
},
"onSale":{
"type":"date",
"format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"desr":{
"type":"text",
"analyzer":"ik_max_word"
}
}
}
}
}
3.2 文档操作
文档中ES服务的唯一标识,
_index
,_type
,_id
三个内容的组合,锁定一个文档,操作是添加还是修改。
3.2.1 新建文档
自动生成一个ID
# 创建文档,自动生成id
POST /book/xuanhuan
{
"name":"盘龙",
"author":"我吃西红柿",
"count":100000,
"onSale":"2001-10-01",
"desr":"第一本玄幻小说,中国大神级之作"
}
手动生成一个ID
# 创建文档,手动创建ID
PUT /book/xuanhuan/1
{
"name":"红楼梦",
"author":"曹雪芹",
"count":500000,
"onSale":"1730-10-01",
"desr":"中国顶级之作,经典之作,四大名著之一"
}
3.2.2 修改文档
覆盖式修改
PUT /book/xuanhaun/1
{
"name":"三国演义",
"author":"罗贯中",
"count":500000,
"onSale":"1730-10-01",
"desr":"中国顶级之作,经典之作,四大名著之一"
}
doc修改方式
POST /book/xuanhuan/WU3TZXMBs7doxP5Q5G_j/_update
{
"doc": {
"name":"西游记"
}
}
3.2.3 删除文档
DELETE /book/xuanhuan/WU3TZXMBs7doxP5Q5G_j
四 结构化查询
4.1 过滤和查询
一条查询语句会计算每个文档与查询语句的相关性,会给出一个相关性评分 _score ,并且按照相关性对匹配到的文档进行排序。 这种评分方式非常适用于一个没有完全配置结果的全文本搜索
性能差异:
使用过滤语句得到的结果集 -- 一个简单的文档列表,快速匹配运算并存入内存是十分方便的, 每个文档仅需要1个字节。这些缓存的过滤结果集与后续请求的结合使用是非常高效的。查询语句不仅要查找相匹配的文档,还需要计算每个文档的相关性,所以一般来说查询语句要比 过滤语句更耗时,并且查询结果也不可缓存。幸亏有了倒排索引,一个只匹配少量文档的简单查询语句在百万级文档中的查询效率会与一条经过缓存 的过滤语句旗鼓相当,甚至略占上风。 但是一般情况下,一条经过缓存的过滤查询要远胜一条查询语句的执行效率。过滤语句的目的就是缩小匹配的文档结果集,所以需要仔细检查过滤条件。
什么情况下使用:
原则上来说,使用查询语句做全文本搜索或其他需要进行相关性评分的时候,剩下的全部用过滤语句
4.1.1 term 过滤
# 查询:term 精确匹配
POST /book/xuanhuan/_search
{
"from": 0,
"size": 2,
"query": {
"term": {
"author": {
"value": "曹雪芹"
}
}
}
}
4.1.2 terms 过滤
POST /book/xuanhuan/_search
{
"from": 0,
"size": 5,
"query": {
"terms": {
"author": [
"曹雪芹",
"施耐庵"
]
}
}
}
4.1.3 range 过滤
# 指定范围查询
# gt:大于
# gte:大于等于
# lt:小于
# lte:小于等于
POST /book/xuanhuan/_search
{
"from": 0,
"size": 5,
"query": {
"range": {
"count": {
"gte": 100000,
"lte": 590000
}
}
}
}
4.1.4 exists 过滤
# 过滤查询文档中是否包含指定字段
POST /book/xuanhuan/_search
{
"from": 0,
"size": 10,
"query": {
"exists": {
"field": "name"
}
}
}
4.1.5 bool 过滤
bool
过滤可以用来合并多个过滤条件查询结果的布尔逻辑,包括以下操作符:
must
:多个查询条件完全匹配,相当于and
。must_not
: 相反匹配,相当于not
。should
: 至少一个查询条件匹配,相当于or
。
# bool过滤
POST /book/xuanhuan/_search
{
"from": 0,
"size": 10,
"query": {
"bool": {
"must": [
{
"term": {
"desr": {
"value": "四大名著"
}
}
},
{
"term": {
"desr": {
"value": "四大名著"
}
}
}
],
"must_not": [
{
"term": {
"count": {
"value": "100000"
}
}
}
],
"should": [
{
"term": {
"desr": {
"value": "四大名著"
}
}
},
{
"term": {
"desr": {
"value": "中国"
}
}
}
]
}
}
}
4.1.6 match_all查询
# 查询所有文档
POST /book/xuanhuan/_search
{
"query": {
"match_all": {}
}
}
4.1.7 match 查询
match
查询是一个标准查询,不管精确查询还是全文查询都会用到它
提示:做精确匹配搜索时,最好用过滤语句,因为过滤语句可以缓存数据。
POST /book/xuanhuan/_search
{
"query": {
"match": {
"name": "三国"
}
}
}
4.1.8 multi_match 查询
multi_match
可以允许在match
查询的基础上同时搜索多个字段:
POST /book/xuanhuan/_search
{
"query": {
"multi_match": {
"query": "中国",
"fields": ["name","desr"]
}
}
}
4.1.9 bool查询
# bool 查询
POST /book/xuanhuan/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"desr": "四大名著"
}
}
],
"should": [
{"match": {
"name": "三国演义"
}},
{
"match": {
"desr": ""
}
}
],
"must_not": [
{
"match": {
"name": "西游记"
}
}
]
}
}
}
4.2 排序
4.2.1 排序方式
为了使结果可以按照相关性进行排序,我们需要一个相关性的值。在
ElasticSearch
的查询结果中, 相关性分值会用_score
字段来给出一个浮点型的数值,所以默认情况下,结果集以_score
进行倒序排列。
4.2.2 字段值排序
字段值默认以顺序排序,而_source
默认以倒序
# 带过滤的查询语句
POST /book/xuanhuan/_search
{
"query": {
"bool": {
"filter": {
"term": {
"desr": "四大名著"
}
}
}
},
"sort": [
{
"count": {
"order": "asc"
}
}
]
}
4.2.3 多级排序
# 多级排序
POST /book/xuanhuan/_search
{
"query": {
"term": {
"desr": {
"value": "之作"
}
}
},
"sort": [
{
"count": {
"order": "desc"
},
"_score":{
"order":"desc"
}
}
]
}
4.2.4 为多值字段排序
在为一个字段的多个值进行排序的时候, 其实这些值本来是没有固定的排序的-- 一个拥有多值的字段就是一个集合, 你准备以哪一个作为排序依据呢?
你可以使用 min , max , avg 或sum 这些模式
# 多级排序
POST /book/xuanhuan/_search
{
"query": {
"term": {
"desr": {
"value": "之作"
}
}
},
"sort":{
"count":{
"order":"asc",
"mode":"avg"
}
}
}
五 Java操作ES
5.1 开发环境搭建
5.1.1 Maven相关jar引入
首先,高版本客户端是依赖低版本客户端,所以要同时引入低版本客户端
其次,客户端只是提供连接,实际操作还需要ES的依赖,所以引入ES依赖。
<!-- ElasticSearch 核心包 -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.5.4</version>
</dependency>
<!--ElasticSearch低版本客户端-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.5.4</version>
</dependency>
<!-- ElasticSearch高版本客户端 -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
5.1.2 Java连接ES
创建测试类,连接ES
public class ESClient {
public static String url = "192.168.75.139";
public static Integer port = 9200;
public static RestHighLevelClient getRestHighLevelClient() {
// 创建HttpHost对象
HttpHost httpHost = new HttpHost(url, port);
// 创建RestClientBuilder
RestClientBuilder restClientBuilder = RestClient.builder(httpHost);
// 创建RestHighLevelClient
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
// 返回
return restHighLevelClient;
}
}
5.2 Java 操作索引
5.2.1 添加索引
先用
kibana
创建person索引,man
类型,Java代码创建时对照这个api进行编写
# 创建索引
PUT /person
{
"settings": {
"number_of_shards": 5,
"number_of_replicas": 1
},
"mappings": {
"man":{
"properties":{
"name":{
"type":"text",
"analyzer":"ik_max_word",
"index":true
},
"age":{
"type":"integer"
},
"birthday":{
"type":"date",
"format":"yyyy-MM-dd"
}
}
}
}
}
Java代码
public class Demo1 {
RestHighLevelClient esClient = ESClient.getRestHighLevelClient();
String index = "person";
String type = "man";
@Test
public void createIndex() throws IOException {
// 1. 准备关于索引的settings
Settings.Builder settings = Settings.builder()
.put("number_of_shards", 5)
.put("number_of_replicas", 1);
// 2. 准备关于索引的结构mapping
XContentBuilder mappings = JsonXContent.contentBuilder()
.startObject()
.startObject("properties")
.startObject("name")
.field("type", "text")
.endObject()
.startObject("age")
.field("type", "integer")
.endObject()
.startObject("birthday")
.field("type", "date")
.field("format", "yyyy-MM-dd")
.endObject()
.endObject()
.endObject();
// 3. 将settings和mappings封装到一个Request对象中
CreateIndexRequest createIndexRequest = new CreateIndexRequest(index)
.settings(settings)
.mapping(type, mappings);
// 4. 通过client连接ES并且执行创建索引
CreateIndexResponse response = esClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
// 5. 输出
System.out.println("resp" + response.toString());
}
}
5.2.2 检查索引
检查索引是否存在
@Tests
public void exists() throws IOException {
//1.准备request对象
GetIndexRequest getIndexRequest = new GetIndexRequest();
getIndexRequest.indices(index);
//2.通过client去操作
boolean exists = esClient.indices().exists(getIndexRequest,RequestOptions.DEFAULT);
System.out.println(index +"存在:"+exists);
}
5.2.3 删除索引
删除索引:在
kabana
中执行DELETE /book
@Test
public void deleteIndex() throws IOException {
//1.创建request对象
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest();
deleteIndexRequest.indices(index);
//2.通过client去操作
AcknowledgedResponse response = esClient.indices().delete(deleteIndexRequest,RequestOptions.DEFAULT);
//3.获取返回结果
System.out.println(response.isAcknowledged());
}
5.3 Java操作文档
5.3.1 添加文档
# 手动添加ID
PUT /person/man/1
{
"name":"张三",
"age":40,
"birthday":"1988-03-07"
}
Java代码添加文档
@Test
public void createDoc() throws IOException, ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
//1.准备json数据
// 在添加时间格式字段时,解决方案:先把时间格式转换成字符串
Person person = new Person(2, "张三", 34, simpleDateFormat.format(new Date()));
String json = mapper.writeValueAsString(person);
//2.通过request对象
IndexRequest indexRequest = new IndexRequest(index, type, person.getId().toString());
indexRequest.source(json, XContentType.JSON);
//3.通过client对象执行添加
IndexResponse indexResponse = esClient.index(indexRequest, RequestOptions.DEFAULT);
//4.输出返回结果
System.out.println(indexResponse.getResult().toString());
}
5.3.2 修改文档
POST /book/xuanhuan/WU3TZXMBs7doxP5Q5G_j/_update
{
"doc": {
"name":"西游记"
}
}
Java代码
@Test
public void updateDoc() throws IOException {
// 1.准备数据:创建一个数据,指定一个需要修改的内容
Map<String, Object> map = new HashMap<>();
map.put("name", "王五");
String docId = "2";
// 2.创建request对象,封装数据
UpdateRequest updateRequest = new UpdateRequest(index, type, docId);
updateRequest.doc(map);
// 3.通过client更新数据
UpdateResponse response = esClient.update(updateRequest, RequestOptions.DEFAULT);
// 4.返回结果
System.out.println(response.getResult().toString());
}
5.3.3 删除文档
DELETE /book/xuanhuan/WU3TZXMBs7doxP5Q5G_j
Java代码
@Test
public void deleteDoc() throws IOException {
// 1.封装Request对象
DeleteRequest deleteRequest = new DeleteRequest(index, type, "3");
// 2.client执行
DeleteResponse response = esClient.delete(deleteRequest, RequestOptions.DEFAULT);
// 3.输出结果
System.out.println(response.getResult().toString());
}
5.3.4 批量操作文档
5.3.4.1 批量添加文档
@Test
public void bulkCreateDoc() throws IOException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
// 1.准备多个json数据
Person p1 = new Person(4, "赵钱孙4", 104, simpleDateFormat.format(new Date()));
Person p2 = new Person(5, "赵钱孙5", 105, simpleDateFormat.format(new Date()));
Person p3 = new Person(6, "赵钱孙6", 106, simpleDateFormat.format(new Date()));
Person p4 = new Person(7, "赵钱孙7", 107, simpleDateFormat.format(new Date()));
String json1 = mapper.writeValueAsString(p1);
String json2 = mapper.writeValueAsString(p2);
String json3 = mapper.writeValueAsString(p3);
String json4 = mapper.writeValueAsString(p4);
// 2.创建Request,将准备好的数据封装进去
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.add(new IndexRequest(index, type, p1.getId().toString()).source(json1, XContentType.JSON));
bulkRequest.add(new IndexRequest(index, type, p2.getId().toString()).source(json2, XContentType.JSON));
bulkRequest.add(new IndexRequest(index, type, p3.getId().toString()).source(json3, XContentType.JSON));
bulkRequest.add(new IndexRequest(index, type, p4.getId().toString()).source(json4, XContentType.JSON));
// 3.用client执行
BulkResponse response = esClient.bulk(bulkRequest, RequestOptions.DEFAULT);
// 4.输出结果
System.out.println(response.toString());
}
5.3.4.2 批量删除文档
@Test
public void bulkDeleteDoc() throws IOException {
// 1.封装Request
BulkRequest request = new BulkRequest();
request.add(new DeleteRequest(index, type, "4"));
request.add(new DeleteRequest(index, type, "5"));
request.add(new DeleteRequest(index, type, "6"));
request.add(new DeleteRequest(index, type, "7"));
// 2.执行client
BulkResponse response = esClient.bulk(request, RequestOptions.DEFAULT);
// 3.输出结果
System.out.println(response.toString());
}
5.4 过滤
5.4.1 term
POST /book/xuanhuan/_search
{
"from": 0,
"size": 2,
"query": {
"term": {
"author": {
"value": "曹雪芹"
}
}
}
}
@Test
public void term() throws IOException {
// 1.创建Request对象
SearchRequest request = new SearchRequest(index);
request.types(type);
// 2.指定查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.from(0);
builder.size(5);
builder.query(QueryBuilders.termQuery("author", "曹雪芹"));
request.source(builder);
// 3.执行查询
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
// 4.获取_source中的数据,并显示
for (SearchHit hit : response.getHits().getHits()) {
Map<String, Object> map = hit.getSourceAsMap();
System.out.println(map);
}
}
5.4.2 terms
POST /book/xuanhuan/_search
{
"from": 0,
"size": 5,
"query": {
"terms": {
"author": [
"曹雪芹",
"施耐庵"
]
}
}
}
@Test
public void terms() throws IOException {
//1.创建Request对象
SearchRequest request = new SearchRequest(index);
request.types(type);
//2.指定查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.from(0);
builder.size(10);
builder.query(QueryBuilders.termsQuery("author", "曹雪芹", "施耐庵"));
request.source(builder);
//3.执行查询
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
//4.获取_soruce中的数据,并显示
for (SearchHit hit : response.getHits().getHits()) {
Map<String, Object> map = hit.getSourceAsMap();
System.out.println(map);
}
}
5.4.3 range
# 指定范围查询
# gt:大于
# gte:大于等于
# lt:小于
# lte:小于等于
POST /book/xuanhuan/_search
{
"from": 0,
"size": 5,
"query": {
"range": {
"count": {
"gte": 100000,
"lte": 590000
}
}
}
}
@Test
public void range() throws IOException {
//1.创建Request对象
SearchRequest request = new SearchRequest(index);
request.types(type);
//2.指定查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.rangeQuery("count").gte(100000).lte(590000));
request.source(builder);
//3.执行查询
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
//4.获取_soruce中的数据,并显示
for (SearchHit hit : response.getHits().getHits()) {
Map<String, Object> map = hit.getSourceAsMap();
System.out.println(map);
}
}
5.4.4 exists
# 过滤查询文档中是否包含指定字段
POST /book/xuanhuan/_search
{
"from": 0,
"size": 10,
"query": {
"exists": {
"field": "name"
}
}
}
@Test
public void exists() throws IOException {
SearchRequest request = new SearchRequest(index);
request.types(type);
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.existsQuery("name"));
request.source(builder);
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
for (SearchHit hit : response.getHits().getHits()) {
Map<String, Object> map = hit.getSourceAsMap();
System.out.println(map);
}
}
5.4.5 bool
bool
过滤可以用来合并多个过滤条件查询结果的布尔逻辑,包括以下操作符:
must
:多个查询条件完全匹配,相当于and
。must_not
: 相反匹配,相当于not
。should
: 至少一个查询条件匹配,相当于or
。
# bool过滤
POST /book/xuanhuan/_search
{
"from": 0,
"size": 10,
"query": {
"bool": {
"must": [
{
"term": {
"desr": {
"value": "四大名著"
}
}
},
{
"term": {
"desr": {
"value": "四大名著"
}
}
}
],
"must_not": [
{
"term": {
"count": {
"value": "100000"
}
}
}
],
"should": [
{
"term": {
"desr": {
"value": "四大名著"
}
}
},
{
"term": {
"desr": {
"value": "中国"
}
}
}
]
}
}
}
@Test
public void bool() throws IOException {
SearchRequest request = new SearchRequest(index);
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.from(0).size(10);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("desr", "四大名著");
boolQueryBuilder.must(termQueryBuilder).must(QueryBuilders.termQuery("desr", "四大名著"));
boolQueryBuilder.mustNot(QueryBuilders.termQuery("count", 100000));
boolQueryBuilder.should(QueryBuilders.termQuery("desr", "四大名著"))
.should(QueryBuilders.termQuery("desr", "中国"));
builder.query(boolQueryBuilder);
request.source(builder);
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
for (SearchHit hit : response.getHits().getHits()) {
Map<String, Object> map = hit.getSourceAsMap();
System.out.println(map);
}
}
5.5 查询
5.5.1 match_all
# 查询所有文档
POST /book/xuanhuan/_search
{
"query": {
"match_all": {}
}
}
@Test
public void matchAll() throws IOException {
// 1.创建Request对象
SearchRequest request = new SearchRequest(index);
request.types(type);
// 2.指定查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.matchAllQuery());
request.source(builder);
// 3.执行查询
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
// 4.获取_soruce中的数据,并显示
for (SearchHit hit : response.getHits().getHits()) {
Map<String, Object> map = hit.getSourceAsMap();
System.out.println(map);
}
}
5.5.2 match
match
查询是一个标准查询,不管精确查询还是全文查询都会用到它
提示:做精确匹配搜索时,最好用过滤语句,因为过滤语句可以缓存数据。
POST /book/xuanhuan/_search
{
"query": {
"match": {
"name": "三国"
}
}
}
@Test
public void match() throws IOException {
// 1.创建Request对象
SearchRequest request = new SearchRequest(index);
request.types(type);
// 2.指定查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.matchQuery("name", "三国"));
request.source(builder);
// 3.执行查询
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
// 4.获取_soruce中的数据,并显示
for (SearchHit hit : response.getHits().getHits()) {
Map<String, Object> map = hit.getSourceAsMap();
System.out.println(map);
}
}
5.5.3 multi_match
multi_match
可以允许在match
查询的基础上同时搜索多个字段:
POST /book/xuanhuan/_search
{
"query": {
"multi_match": {
"query": "中国",
"fields": ["name","desr"]
}
}
}
@Test
public void multiMatch() throws IOException {
// 1.创建Request对象
SearchRequest request = new SearchRequest(index);
request.types(type);
// 2.指定查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.from(0).size(10);
builder.query(QueryBuilders.multiMatchQuery("中国", "name", "desr"));
request.source(builder);
// 3.执行查询
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
// 4.获取_soruce中的数据,并显示
for (SearchHit hit : response.getHits().getHits()) {
Map<String, Object> map = hit.getSourceAsMap();
System.out.println(map);
}
}
5.5.4 bool
# bool 查询
POST /book/xuanhuan/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"desr": "四大名著"
}
}
],
"should": [
{"match": {
"name": "三国演义"
}},
{
"match": {
"desr": ""
}
}
],
"must_not": [
{
"match": {
"name": "西游记"
}
}
]
}
}
}
@Test
public void searchBool() throws IOException {
// 1.request
SearchRequest request = new SearchRequest(index);
request.types(type);
// 2.指定查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("desr", "四大名著"))
.should(QueryBuilders.matchQuery("name", "三国演义"))
.should(QueryBuilders.matchQuery("desr", ""))
.mustNot(QueryBuilders.matchQuery("name", "西游记"))
);
request.source(builder);
// 3.执行查询
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
// 4.返回查询结果
for (SearchHit hit : response.getHits().getHits()) {
Map<String, Object> map = hit.getSourceAsMap();
System.out.println(map);
}
}