从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • RSS
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 📖 读书

    • 读书工具
    • 读书笔记
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • RSS
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 📖 读书

    • 读书工具
    • 读书笔记
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

    • Redis

    • Mybatis

    • Lucene

    • Elasticsearch

      • Elasticsearch 简介
      • ES 的安装和启动
      • ES 相关术语
      • ES 索引库的维护
      • ES 索引库的查询
      • ES 集成 IK 分词器
      • ES 集群
      • 使用 Java 操作 ES
      • 使用 Java 查询 ES
        • 查询步骤
        • 根据 id 搜索
        • 根据 Term 查询(关键词)
        • 抽取通用代码
        • QueryString 查询方式(带分析的查询)
        • 分页的处理
        • 查询结果高亮显示
        • 源码
      • SpringDataElasticSearch
    • MQ

    • MyCat

    • Lombok

  • SpringMVC

  • SpringBoot

  • Java
  • 主流框架
  • Elasticsearch
2023-05-22
目录

使用 Java 查询 ES

# 70.使用 Java 查询 ES

接下来我们说说更常见的操作:查询

‍

# 查询步骤

不管是根据什么方式查询,步骤都是类似的:

  1. 创建一个 Client 对象
  2. 创建一个查询对象,可以使用 QueryBuilders 工具类创建 QueryBuilder 对象。
  3. 使用 Client 执行查询
  4. 得到查询的结果
  5. 取查询结果的总记录数
  6. 取查询结果列表
  7. 关闭 Client ‍ 我们先创建初始化和销毁方法,减少重复代码:
package com.peterjxl.es;

import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.After;
import org.junit.Before;

import java.net.InetAddress;

public class SearchIndex {
    private TransportClient client;

    @Before
    public void init() throws Exception{
        Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
        client = new PreBuiltTransportClient(settings)
  .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9301))
  .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9302))
  .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9303));
    }
  
    @After
    public void close() {
        client.close();
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

‍

# 根据 id 搜索

示例代码:

@Test
    public void searchIndexWithID() {
        QueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds("3", "4");
        SearchResponse searchResponse = client.prepareSearch("index_hello")
                .setTypes("article")
                .setQuery(queryBuilder)
                .get();
        SearchHits searchHits = searchResponse.getHits();

        System.out.println("查询结果总记录数" + searchHits.getTotalHits());
        Iterator<SearchHit> iterator = searchHits.iterator();
        while (iterator.hasNext()) {
            SearchHit searchHit = iterator.next();
            System.out.println(searchHit.getSourceAsString());
          
            System.out.println("文档的属性: ");
            Map<String, Object> document = searchHit.getSource();
            System.out.println("id:" + document.get("id"));
            System.out.println("title:" + document.get("title"));
            System.out.println("content:" + document.get("content"));
            System.out.println("-------------------------- ");
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

‍ 关键在于:

QueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds("3", "4");
1

‍ 运行结果:

查询结果总记录数2
{"id":4,"title":"关于买房","content":"虚假的挥霍:花几千块钱去看看海。真正的挥霍:花100万交个首付买一个名义面积70平,实际面积55平,再还30年贷款的小户型住房"}
文档的属性: 
id:4
title:关于买房
content:虚假的挥霍:花几千块钱去看看海。真正的挥霍:花100万交个首付买一个名义面积70平,实际面积55平,再还30年贷款的小户型住房
-------------------------- 
{"id":3,"title":"关于梦想","content":"编程对我而言,就像是一颗小小的,微弱的希望的种子,我甚至都不愿意让人看见它。生怕有人看见了便要嘲讽它,它太脆弱了,经不起别人的质疑"}
文档的属性: 
id:3
title:关于梦想
content:编程对我而言,就像是一颗小小的,微弱的希望的种子,我甚至都不愿意让人看见它。生怕有人看见了便要嘲讽它,它太脆弱了,经不起别人的质疑
-------------------------- 
1
2
3
4
5
6
7
8
9
10
11
12
13

# 根据 Term 查询(关键词)

QueryBuilder queryBuilder = QueryBuilders.termQuery("title", "北方");
‍

@Test
public void searchIndexWithTerm() {
    QueryBuilder queryBuilder = QueryBuilders.termQuery("title", "梦想");
    SearchResponse searchResponse = client.prepareSearch("index_hello")
            .setTypes("article")
            .setQuery(queryBuilder)
            .get();
    SearchHits searchHits = searchResponse.getHits();
    System.out.println("查询结果总记录数" + searchHits.getTotalHits());
    Iterator<SearchHit> iterator = searchHits.iterator();
    while (iterator.hasNext()) {
        SearchHit searchHit = iterator.next();
        System.out.println(searchHit.getSourceAsString());

        System.out.println("文档的属性: ");
        Map<String, Object> document = searchHit.getSource();
        System.out.println("id:" + document.get("id"));
        System.out.println("title:" + document.get("title"));
        System.out.println("content:" + document.get("content"));
        System.out.println("-------------------------- ");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

‍ 关键在于:

QueryBuilder queryBuilder = QueryBuilders.termQuery("title", "梦想");
1

# 抽取通用代码

我们可以看到,通过 id 和通过 term 查询,只有 QueryBuilder 是不一样的,其他的查询和打印都是一样的,我们可以做成一个通用的方法:

public void search(QueryBuilder queryBuilder){
        SearchResponse searchResponse = client.prepareSearch("index_hello")
                .setTypes("article")
                .setQuery(queryBuilder)
                .get();
        SearchHits searchHits = searchResponse.getHits();
        System.out.println("查询结果总记录数" + searchHits.getTotalHits());

        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getSourceAsString());
            System.out.println("文档的属性: ");
            Map<String, Object> document = searchHit.getSource();
            System.out.println("id:" + document.get("id"));
            System.out.println("title:" + document.get("title"));
            System.out.println("content:" + document.get("content"));
            System.out.println("-------------------------- ");
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

这样其他两个方法就简单了:

@Test
public void searchIndexWithID() {
    QueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds("3", "4");
    search(queryBuilder);
}


@Test
public void searchIndexWithTerm() {
    QueryBuilder queryBuilder = QueryBuilders.termQuery("title", "梦想");
    search(queryBuilder);
}
1
2
3
4
5
6
7
8
9
10
11
12

‍

# QueryString 查询方式(带分析的查询)

示例:

@Test
public void searchIndexWithQueryString() {
    QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("梦想是什么");
    search(queryBuilder);
}
1
2
3
4
5

‍ 此时会在所有域中进行查询,查询结果:

查询结果总记录数1
{"id":3,"title":"关于梦想","content":"编程对我而言,就像是一颗小小的,微弱的希望的种子,我甚至都不愿意让人看见它。生怕有人看见了便要嘲讽它,它太脆弱了,经不起别人的质疑"}
文档的属性: 
id:3
title:关于梦想
content:编程对我而言,就像是一颗小小的,微弱的希望的种子,我甚至都不愿意让人看见它。生怕有人看见了便要嘲讽它,它太脆弱了,经不起别人的质疑
-------------------------- 
1
2
3
4
5
6
7

‍ 如果要指定默认搜索域:

QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("梦想是什么").defaultField("title");
1

‍

# 分页的处理

有时候查询出来多个结果,此时就需要分页:在 Client 对象执行查询之前,设置分页信息,然后再执行查询

# 添加多条数据

为了更好的演示分页效果,我们使用循环添加多条数据。在 ElasticsearchClientTest.java 中添加方法:

@Test
public void testAddDocument3() throws Exception {
    for (int i = 5; i < 100; i++){
        // 创建一个Article对象,设置对象的属性
        Article article = new Article();
        article.setId((long) i);
        article.setTitle("关于生活" + i);
        article.setContent("1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难" + i);

        // 把Article对象转换为JSON格式的字符串
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonDocument = objectMapper.writeValueAsString(article);

        // 把文档写入索引库
        client.prepareIndex("index_hello", "article", article.getId().toString())
                .setSource(jsonDocument, XContentType.JSON)
                .get();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

‍ 此时能看到有很多数据了:

‍

# 设置分页

即使不设置分页,默认也是会分页,每页 10 条(读者可以自行测试下)。

@Test
    public void searchIndexWithPaging() {
        QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("生活是什么").defaultField("title");
        SearchResponse searchResponse = client.prepareSearch("index_hello")
                .setTypes("article")
                .setQuery(queryBuilder)
                .setFrom(0) // 起始记录下标
                .setSize(5) // 每页显示的记录数
                .get();
        SearchHits searchHits = searchResponse.getHits();
        System.out.println("查询结果总记录数" + searchHits.getTotalHits());

        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getSourceAsString());
            System.out.println("文档的属性: ");
            Map<String, Object> document = searchHit.getSource();
            System.out.println("id:" + document.get("id"));
            System.out.println("title:" + document.get("title"));
            System.out.println("content:" + document.get("content"));
            System.out.println("-------------------------- ");
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

‍ 分页需要设置两个值,from:起始的行号,从 0 开始。size:每页显示的记录数。查询结果:

查询结果总记录数95
{"id":35,"title":"关于生活35","content":"1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难35"}
文档的属性: 
id:35
title:关于生活35
content:1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难35
-------------------------- 
{"id":36,"title":"关于生活36","content":"1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难36"}
文档的属性: 
id:36
title:关于生活36
content:1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难36
-------------------------- 
{"id":38,"title":"关于生活38","content":"1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难38"}
文档的属性: 
id:38
title:关于生活38
content:1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难38
-------------------------- 
{"id":54,"title":"关于生活54","content":"1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难54"}
文档的属性: 
id:54
title:关于生活54
content:1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难54
-------------------------- 
{"id":55,"title":"关于生活55","content":"1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难55"}
文档的属性: 
id:55
title:关于生活55
content:1对夫妻2个打工人带3个孩子养4个父母月薪5千掏空6个钱包7天无休8十万买的房子不到9十平米生活10分困难55
-------------------------- 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

‍

# 查询结果高亮显示

在使用搜索引擎的过程中,关键词会被高亮显示:例如字体变为红色

‍

Elasticsearch 也支持,配置步骤:

  1. 设置高亮显示的字段(Field),前缀和后缀(例如 HTML 标签中有个 <em>,可以加粗显示字体)
  2. 在 Clinet 对象执行查询之前,设置高亮显示的信息。
  3. 遍历结果列表时可以从结果中取高亮结果。 ‍ 示例:
@Test
public void searchIndexWithHighLight() {
    HighlightBuilder highlightBuilder = new HighlightBuilder();
    highlightBuilder.field("title");
    highlightBuilder.preTags("<em>");
    highlightBuilder.postTags("</em>");

    QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("梦想").defaultField("title");
    SearchResponse searchResponse = client.prepareSearch("index_hello")
            .setTypes("article")
            .setQuery(queryBuilder)
            .highlighter(highlightBuilder)
            .get();
    SearchHits searchHits = searchResponse.getHits();
    System.out.println("查询结果总记录数:" + searchHits.getTotalHits());
    for (SearchHit searchHit : searchHits) {
        System.out.println("高亮结果: ");
        Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
        System.out.println(highlightFields);

        // 遍历高亮字段
        HighlightField highlightField = highlightFields.get("title");
        Text[] fragments = highlightField.getFragments();
        if(fragments != null){
            String title = fragments[0].toString();
            System.out.println("title: " + title);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

‍ 运行结果:

查询结果总记录数:1
高亮结果: 
{title=[title], fragments[[关于<em>梦想</em>]]}
title: 关于<em>梦想</em>
1
2
3
4

# 源码

本项目已将源码上传到 Gitee (opens new window) 和 GitHub (opens new window) 上。并且创建了分支 demo2,读者可以通过切换分支来查看本文的示例代码

上次更新: 2025/5/17 12:26:09
使用 Java 操作 ES
SpringDataElasticSearch

← 使用 Java 操作 ES SpringDataElasticSearch→

最近更新
01
吐槽一下《僵尸校园》
05-15
02
2025 年 4 月记
04-30
03
山西大同 “订婚强奸案” 将会给整个社会带来的影响有多严重? - 知乎 转载
04-26
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式