专业的编程技术博客社区

网站首页 > 博客文章 正文

搜索技术 四)——java实现ElasticSearch客户端

baijin 2025-03-01 12:47:57 博客文章 13 ℃ 0 评论

4.ES的Java客户端

在elasticsearch官网中提供了各种语言的客户端:
https://www.elastic.co/guide/en/elasticsearch/client/index.html

而Java的客户端就有两个:

不过Java API这个客户端(Transport Client)已经在7.0以后过期了,而且在8.0版本中将直接废弃


Java REST Client 其实就是利用Java语言向 ES服务发 Http的请求

3.1.准备数据库数据

我们需要从数据库导入数据到ES中,因此需要做一些准备:

  • 引入依赖
  • 执行sql,准备数据
  • 引入实体类
  • 引入mybatis相关配置
  • 引入mapper和service代码

3.1.1.引入依赖

在项目的pom文件中引入一些依赖:

org.elasticsearch.client

elasticsearch-rest-high-level-client

7.4.2

3.1.2.执行sql

3.1.3.引入实体类

3.1.4.引入mybatis配置

3.1.5.引入mapper和Service

此处均省略,大家可自行配置

3.2.连接ElasticSearch

在官网上可以看到连接ES的教程:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-getting-started-initialization.html

首先需要与ES建立连接,ES提供了一个客户端RestHighLevelClient。

代码如下:


RestHighLevelClient client = new RestHighLevelClient(
 ? ? ? ? ? ? ? ?RestClient.builder(
 ? ? ? ? ? ? ? ? ? ? ? ?new HttpHost("localhost", 9200, "http"),
 ? ? ? ? ? ? ? ? ? ? ? ?new HttpHost("localhost", 9201, "http"),
 ? ? ? ? ? ? ? ? ? ? ? ?new HttpHost("localhost", 9202, "http")
 ? ? ? ? ? ? ?  )
 ? ? ?  );

ES中的所有操作都是通过RestHighLevelClient来完成的:



为了后面测试方便,我们写到一个单元测试中,并且通过@Before注解来初始化客户端连接。

/**

*

*/

public class ElasticDemo {

private RestHighLevelClient client;

/**

* 建立连接

*/

@Before

public void init() throws IOException {

client = new RestHighLevelClient(

RestClient.builder(

new HttpHost("localhost", 9200, "http"),

new HttpHost("localhost", 9201, "http"),

new HttpHost("localhost", 9202, "http")

)

);

}

/**

* 关闭客户端连接

*/

@After

public void close() throws IOException {

client.close();

}

}

4.Java实现创建库和映射

开发中,往往库和映射的操作一起完成,官网详细文档地址:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/_index_apis.html


4.1.思路分析

按照官网给出的步骤,创建索引包括下面几个步骤:

  • 1)创建CreateIndexRequest对象,并指定索引库名称
  • 2)指定settings配置
  • 3)指定mapping配置
  • 4)发起请求,得到响应

其实仔细分析,与我们在Kibana中的Rest风格API完全一致:

PUT /heima
{
 ?"settings": {
 ? ?"number_of_shards": 3,
 ? ?"number_of_replicas": 1
  },
 ?"mappings": {
 ? ?
  }
}

4.2.设计映射规则

Java代码中设置mapping,依然与REST中一致,需要JSON风格的映射规则。因此我们先在kibana中给User实体类定义好映射规则。

User包括下面的字段:

  • Id:主键,在ES中是唯一标示,数字,可以选择long类型
  • name:姓名,字符串类型,但是无需分词,使用keyword,也无需查找,index为false
  • age:年龄,整数,可以使用integer
  • gender:性别,字符串类型,但是无需分词,使用keyword
  • note:备注,用户详细信息,字符串类型。需要分词,使用text

4.3.代码实现

我们在上面新建的ElasticDemo类中新建单元测试,完成代码,思路就是之前分析的4步骤:

  • 1)创建CreateIndexRequest对象,并指定索引库名称
  • 2)指定settings配置
  • 3)指定mapping配置
  • 4)发起请求,得到响应

private RestHighLevelClient client;

@Test

public void testCreateIndex() throws IOException {

// 1.创建CreateIndexRequest对象,并指定索引库名称

CreateIndexRequest request = new CreateIndexRequest("user");

// 2.指定settings配置

request.settings(Settings.builder()

.put("index.number_of_shards", 3)

.put("index.number_of_replicas", 1)

);

// 3.指定mapping配置

request.mapping(

"{\n" +

" \"properties\": {\n" +

" \"id\": {\n" +

" \"type\": \"long\"\n" +

" },\n" +

" \"name\":{\n" +

" \"type\": \"keyword\"\n" +

" },\n" +

" \"age\":{\n" +

" \"type\": \"integer\"\n" +

" },\n" +

" \"gender\":{\n" +

" \"type\": \"keyword\"\n" +

" },\n" +

" \"note\":{\n" +

" \"type\": \"text\",\n" +

" \"analyzer\": \"ik_max_word\"\n" +

" }\n" +

" }\n" +

" }",

XContentType.JSON);

// 4.发起请求,得到响应

CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);

System.out.println("response = " + response.isAcknowledged());

}

5.Java实现文档的CRUD

文档操作包括:新增文档、查询文档、修改文档、删除文档等。

官网地址:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/java-rest-high-supported-apis.html

5.1.新增

官网地址:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/java-rest-high-document-index.html

5.1.1.实现思路

根据官网文档,实现的步骤如下:

  • 1)创建IndexRequest对象,并指定索引库名称
  • 2)指定新增的数据的id
  • 3)将新增的文档数据变成JSON格式
  • 4)将JSON数据添加到IndexRequest中
  • 5)发起请求,得到结果

不过,我们的文档数据需要去查询数据库,因此前面会多出一个步骤:从数据库查询文档数据

  • 1)从数据库查询文档数据
  • 2)创建IndexRequest对象,并指定索引库名称
  • 3)指定新增的数据的id
  • 4)将新增的文档数据变成JSON格式
  • 5)将JSON数据添加到IndexRequest中
  • 6)发起请求,得到结果

5.1.2.具体代码

需要在单元测试类中线初始化UserService对象:


private UserService userService = new UserService();

新增文档:


@Test
public void addDocument() throws IOException {
 ? ?// 1.从数据库查询文档数据
 ? ?User user = userService.findById(6L);
 ? ?// 2.创建IndexRequest对象,并指定索引库名称
 ? ?IndexRequest request = new IndexRequest("user");
 ? ?// 3.指定新增的数据的id,这里的id一定要用string
 ? ?request.id(user.getId().toString());
 ? ?// 4.将新增的文档数据变成JSON格式
 ? ?String jsonString = JSON.toJSONString(user);
 ? ?// 5.将JSON数据添加到IndexRequest中
 ? ?request.source(jsonString, XContentType.JSON);
 ? ?// 6.发起请求,得到结果
 ? ?IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);

 ? ?System.out.println("indexResponse = " + indexResponse.getResult());
}

结果:

indexResponse = CREATED


5.1.3.新增的ID一致时

我们直接测试过,新增的时候如果ID存在则变成修改,我们试试,再次执行刚才的代码,可以看到结果变了

5.2.查询文档

官网地址:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/java-rest-high-document-get.html

5.2.1.实现思路

这里的查询是根据id查询,必须知道文档的id才可以。

根据官网文档,实现的步骤如下:

  • 1)创建GetRequest 对象,并指定索引库名称、文档ID
  • 2)发起请求,得到结果
  • 3)从结果中得到source,是json字符串
  • 4)将JSON反序列化为对象

5.2.2.具体代码


@Test
public void getDocument() throws IOException {
 ? ?// 1.创建GetRequest对象,并指定索引库名称、文档ID
 ? ?GetRequest request = new GetRequest("user", "6");
 ? ?// 2.发起请求,得到结果
 ? ?GetResponse response = client.get(request, RequestOptions.DEFAULT);
 ? ?// 3.从结果中得到source,是json字符串
 ? ?String source = response.getSourceAsString();
 ? ?// 4.将JSON反序列化为对象
 ? ?User user = JSON.parseObject(source, User.class);

 ? ?System.out.println("user = " + user);
}

结果如下:


user = User(id=6, name=李磊, age=23, gender=男, note=李磊同学在传智播客学Java)


5.3.修改文档

新增时,如果ID一致就会覆盖旧的数据,实现修改。不过,如果我们只修改文档中的某个字段,可以使用另外的API:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/java-rest-high-document-update.html

5.3.1.思路

根据官网信息,修改时需要指定某个已经存在的文档的id、然后指定要修改的字段及新的值。

基本步骤如下:

  • 1.创建UpdateRequest对象,指定索引库名称、文档ID
  • 2.指定要修改的字段及属性值
  • 3.发起请求

5.3.2.代码实现


@Test
public void updateDocument() throws IOException {
 ? ?// 1.创建UpdateRequest对象,指定索引库名称、文档ID
 ? ?UpdateRequest request = new UpdateRequest(
 ? ? ? ?"user",
 ? ? ? ?"6");
 ? ?// 2.指定要修改的字段及属性值
 ? ?request.doc("gender", "女");
 ? ?// 3.发起请求
 ? ?UpdateResponse updateResponse = client.update(
 ? ? ? ?request, RequestOptions.DEFAULT);

 ? ?System.out.println("updateResponse = " + updateResponse.getResult());
}

结果如下:


updateResponse = UPDATED

如果再次查询

user = User(id=6, name=李磊, age=23, gender=女, note=柳岩同学在欢哥身边跳舞)



5.4.删除文档

官网地址:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/java-rest-high-document-delete.html

实现思路非常简单,直接根据ID删除即可:

  • 1.创建DeleteRequest对象,指定索引库名称、文档ID
  • 2.发起请求

代码实现:


@Test
public void deleteDocument() throws IOException {
 ? ?// 1.创建DeleteRequest对象,指定索引库名称、文档ID
 ? ?DeleteRequest request = new DeleteRequest(
 ? ? ? ?"user",
 ? ? ? ?"6");
 ? ?// 2.发起请求
 ? ?DeleteResponse deleteResponse = client.delete(
 ? ? ? ?request, RequestOptions.DEFAULT);

 ? ?System.out.println("deleteResponse = " + deleteResponse.getResult());
}

结果:

deleteResponse = DELETED



5.5.批处理

如果我们需要把数据库中的所有用户信息都导入索引库,可以批量查询出多个用户,但是刚刚的新增文档是一次新增一个文档,这样效率太低了。

因此ElasticSearch提供了批处理的方案:BulkRequest

https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/java-rest-high-document-bulk.html

5.5.1.思路分析

A BulkRequest can be used to execute multiple index, update and/or delete operations using a single request.

一个BulkRequest可以在一次请求中执行多个 新增、更新、删除请求。

所以,BulkRequest就是把多个其它增、删、改请求整合,然后一起发送到ES来执行。

我们拿批量新增来举例,步骤如下:

  • 1.从数据库查询文档数据
  • 2.创建BulkRequest对象
  • 3.创建多个IndexRequest对象,组织文档数据,并添加到BulkRequest中
  • 4.发起请求

5.5.2.具体代码


@Test
public void testBulk() throws IOException {
 ? ?// 1.从数据库查询文档数据
 ? ?List list = userService.findAll();
 ? ?// 2.创建BulkRequest对象
 ? ?BulkRequest bulkRequest = new BulkRequest();
 ? ?// 3.创建多个IndexRequest对象,并添加到BulkRequest中
 ? ?for (User user : list) {
 ? ? ? ?bulkRequest.add(new IndexRequest("user")
 ? ? ? ? ? ? ? ? ? ? ?  .id(user.getId().toString())
 ? ? ? ? ? ? ? ? ? ? ?  .source(JSON.toJSONString(user), XContentType.JSON)
 ? ? ? ? ? ? ? ? ? ? ? );
 ?  }
 ? ?// 4.发起请求
 ? ?BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);

 ? ?System.out.println("status: " + bulkResponse.status());
}

结果如下:

status: OK



6.Java实现搜索

查询、搜索相关功能主要包括:

  • 基本查询:query分词查询:match查询词条查询:term查询范围查询:range查询布尔查询:bool查询filter功能
  • 排序:sort
  • 分页:from和size
  • 高亮:highlight
  • source过滤

官方文档:
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/java-rest-high-search.html

6.1.搜索的核心API

先来看下REST风格中查询的语法:

整个请求对象是一个大JSON对象,包含5部分属性:

  • query:查询属性
  • sort:排序属性
  • from和size:分页属性
  • highlight:高亮属性
  • aggs:聚合属性

而Java客户端,其实也是在构建这样的JSON对象。

6.1.1.SearchSourceBuilder

在Java客户端中,SearchSourceBuilder就是用来构建上面提到的大JSON对象,其中包含了5个方法:

  • query(QueryBuilder):查询条件
  • sort(String, SortOrder):排序条件
  • from(int)和size(int):分页条件
  • highlight(HighlightBuilder):高亮条件
  • aggregation(AggregationBuilder):聚合条件

搜索得到的结果整体是一个JSON对象,包含下列2个属性:

  • hits:查询结果,其中又包含两个属性:total:总命中数量hits:查询到的文档数据,是一个数组,数组中的每个对象就包含一个文档结果,又包含:_source:文档原始信息highlight:高亮结果信息
  • aggregations:聚合结果对象,其中包含多个属性,属性名称由添加聚合时的名称来确定:gender_agg:这个是我们创建聚合时用的聚合名称,其中包含聚合结果buckets:聚合结果数组

Java客户端中的SearchResponse代表整个JSON结果

6.2.1.SearchResponse

Java客户端中的SearchResponse代表整个JSON结果,包含下面的方法:

包含两个方法:

  • getHits():返回的是SearchHits,代表查询结果
  • getAggregations():返回的是Aggregations,代表聚合结果

6.2.2.SearchHits查询结果

SearchHits代表查询结果的JSON对象:

核心方法有3个:

  • getHits():返回SearchHit数组
  • getMaxScore():返回float,文档的最大得分
  • getTotalHists():返回TotalHists,总命中数

6.2.3.SearchHit结果对象

  • getSourceAsString():返回的是_source
  • getHighLightFields():返回是高亮结果

6.3.基本查询


6.3.1.思路分析

步骤如下:

  • 1.创建SearchSourceBuilder对象1.1.添加查询条件QueryBuilders1.2.添加排序、分页等其它条件
  • 2.创建SearchRequest对象,并制定索引库名称
  • 3.添加SearchSourceBuilder对象到SearchRequest对象中
  • 4.发起请求,得到结果
  • 5.解析结果5.1.获取总条数5.2.获取SearchHits数组,并遍历获取其中的_source,是JSON数据把_source反序列化为User对象

6.3.2.查询所有

QueryBuilders可以实现各种查询,比如查询所有:match_all

代码如下:

@Test
public void testBasicSearch() throws IOException {
 ? ?// 1.创建SearchSourceBuilder对象
 ? ?SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 ? ?//  1.1.添加查询条件QueryBuilders,这里选择match_all,查询所有
 ? ?sourceBuilder.query(QueryBuilders.matchAllQuery());
 ? ?//  1.2.添加排序、分页等其它条件

 ? ?// 2.创建SearchRequest对象,并制定索引库名称
 ? ?SearchRequest request = new SearchRequest("user");
 ? ?// 3.添加SearchSourceBuilder对象到SearchRequest对象中
 ? ?request.source(sourceBuilder);
 ? ?// 4.发起请求,得到结果
 ? ?SearchResponse response = client.search(request, RequestOptions.DEFAULT);
 ? ?// 5.解析结果
 ? ?SearchHits searchHits = response.getHits();
 ? ?//  5.1.获取总条数
 ? ?long total = searchHits.getTotalHits().value;
 ? ?System.out.println("total = " + total);
 ? ?//  5.2.获取SearchHits数组,并遍历
 ? ?SearchHit[] hits = searchHits.getHits();
 ? ?for (SearchHit hit : hits) {
 ? ? ? ?//  - 获取其中的`_source`,是JSON数据
 ? ? ? ?String json = hit.getSourceAsString();
 ? ? ? ?//  - 把`_source`反序列化为User对象
 ? ? ? ?User user = JSON.parseObject(json, User.class);
 ? ? ? ?System.out.println("user = " + user);
 ?  }
}

结果如下

total = 5

user = User(id=5, name=李娜, age=28, gender=女, note=李娜同学在欢哥房间学画画)

user = User(id=2, name=李四, age=21, gender=男, note=李四同学在华为敲代码)

user = User(id=4, name=张伟, age=20, gender=男, note=张伟同学在交友软件谈恋爱)

user = User(id=10, name=范冰冰, age=25, gender=女, note=范冰冰同学在欢哥旁边表演)

user = User(id=8, name=柳岩, age=21, gender=女, note=柳岩同学在欢哥旁边唱歌)

6.3.3.分词查询

MatchQuery就是分词查询,会对搜索的内容分词后查询:


sourceBuilder.query(QueryBuilders.matchQuery("note", "唱歌表演"));

完整代码如下:


@Test
public void testBasicSearch() throws IOException {
 ? ?// 1.创建SearchSourceBuilder对象
 ? ?SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 ? ?//  1.1.添加查询条件QueryBuilders,这里选择match_all,查询所有
 ? ?// ? ? ?  sourceBuilder.query(QueryBuilders.matchAllQuery());
 ? ?sourceBuilder.query(QueryBuilders.matchQuery("note", "唱歌表演"));
 ? ?//  1.2.添加排序、分页等其它条件

 ? ?// 2.创建SearchRequest对象,并制定索引库名称
 ? ?SearchRequest request = new SearchRequest("user");
 ? ?// 3.添加SearchSourceBuilder对象到SearchRequest对象中
 ? ?request.source(sourceBuilder);
 ? ?// 4.发起请求,得到结果
 ? ?SearchResponse response = client.search(request, RequestOptions.DEFAULT);
 ? ?// 5.解析结果
 ? ?SearchHits searchHits = response.getHits();
 ? ?//  5.1.获取总条数
 ? ?long total = searchHits.getTotalHits().value;
 ? ?System.out.println("total = " + total);
 ? ?//  5.2.获取SearchHits数组,并遍历
 ? ?SearchHit[] hits = searchHits.getHits();
 ? ?for (SearchHit hit : hits) {
 ? ? ? ?//  - 获取其中的`_source`,是JSON数据
 ? ? ? ?String json = hit.getSourceAsString();
 ? ? ? ?//  - 把`_source`反序列化为User对象
 ? ? ? ?User user = JSON.parseObject(json, User.class);
 ? ? ? ?System.out.println("user = " + user);
 ?  }
}

结果:

total = 2
user = User(id=10, name=范冰冰, age=25, gender=女, note=范冰冰同学在欢哥旁边表演)
user = User(id=8, name=柳岩, age=21, gender=女, note=柳岩同学在欢哥旁边唱歌)


6.3.4.布尔查询

BooleanQuery就是布尔查询,需要把其它几个查询用must、must_not组合,另外过滤条件最好使用filter来实现。比如:


// 布尔查询
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
// 添加must条件
queryBuilder.must(QueryBuilders.matchQuery("note", "唱歌表演"));
// 添加filter条件,不参与打分
queryBuilder.filter(QueryBuilders.rangeQuery("age").gte(18).lte(24));
sourceBuilder.query(queryBuilder);

完整代码:


@Test
public void testBasicSearch() throws IOException {
 ? ?// 1.创建SearchSourceBuilder对象
 ? ?SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 ? ?//  1.1.添加查询条件QueryBuilders,这里选择match_all,查询所有
 ? ?// ? ? ?  sourceBuilder.query(QueryBuilders.matchAllQuery());
 ? ?// ? ? ?  sourceBuilder.query(QueryBuilders.matchQuery("note", "唱歌表演"));

 ? ?// 布尔查询
 ? ?BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
 ? ?// 添加must条件
 ? ?queryBuilder.must(QueryBuilders.matchQuery("note", "唱歌表演"));
 ? ?// 添加filter条件,不参与打分
 ? ?queryBuilder.filter(QueryBuilders.rangeQuery("age").gte(18).lte(24));
 ? ?sourceBuilder.query(queryBuilder);
 ? ?//  1.2.添加排序、分页等其它条件

 ? ?// 2.创建SearchRequest对象,并制定索引库名称
 ? ?SearchRequest request = new SearchRequest("user");
 ? ?// 3.添加SearchSourceBuilder对象到SearchRequest对象中
 ? ?request.source(sourceBuilder);
 ? ?// 4.发起请求,得到结果
 ? ?SearchResponse response = client.search(request, RequestOptions.DEFAULT);
 ? ?// 5.解析结果
 ? ?SearchHits searchHits = response.getHits();
 ? ?//  5.1.获取总条数
 ? ?long total = searchHits.getTotalHits().value;
 ? ?System.out.println("total = " + total);
 ? ?//  5.2.获取SearchHits数组,并遍历
 ? ?SearchHit[] hits = searchHits.getHits();
 ? ?for (SearchHit hit : hits) {
 ? ? ? ?//  - 获取其中的`_source`,是JSON数据
 ? ? ? ?String json = hit.getSourceAsString();
 ? ? ? ?//  - 把`_source`反序列化为User对象
 ? ? ? ?User user = JSON.parseObject(json, User.class);
 ? ? ? ?System.out.println("user = " + user);
 ?  }
}


结果:

total = 1
user = User(id=8, name=柳岩, age=21, gender=女, note=柳岩同学在欢哥旁边唱歌)


6.4.source过滤

在原来搜索的基础上,通过SearchSourceBuilder的fetchSource(String[] includes, String[] excludes)方法实现:

  • includes:包含的字段
  • excludes:要排除的字段

代码:


// 2.source过滤,指定includes,只要id、name、note
sourceBuilder.fetchSource(new String[]{"id", "name", "note"}, new String[0]);

完整代码:


@Test
public void testBasicSearch() throws IOException {
 ? ?// 1.创建SearchSourceBuilder对象
 ? ?SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 ? ?//  1.1.添加查询条件QueryBuilders,这里选择match_all,查询所有
 ? ?sourceBuilder.query(QueryBuilders.matchQuery("note", "唱歌表演"));

 ? ?// 2.source过滤,指定includes,只要id、name、note
 ? ?sourceBuilder.fetchSource(new String[]{"id", "name", "note"}, new String[0]);

 ? ?// 3.创建SearchRequest对象,并制定索引库名称
 ? ?SearchRequest request = new SearchRequest("user");
 ? ?// 4.添加SearchSourceBuilder对象到SearchRequest对象中
 ? ?request.source(sourceBuilder);
 ? ?// 5.发起请求,得到结果
 ? ?SearchResponse response = client.search(request, RequestOptions.DEFAULT);
 ? ?// 6.解析结果
 ? ?SearchHits searchHits = response.getHits();
 ? ?//  6.1.获取总条数
 ? ?long total = searchHits.getTotalHits().value;
 ? ?System.out.println("total = " + total);
 ? ?//  6.2.获取SearchHits数组,并遍历
 ? ?SearchHit[] hits = searchHits.getHits();
 ? ?for (SearchHit hit : hits) {
 ? ? ? ?//  - 获取其中的`_source`,是JSON数据
 ? ? ? ?String json = hit.getSourceAsString();
 ? ? ? ?//  - 把`_source`反序列化为User对象
 ? ? ? ?User user = JSON.parseObject(json, User.class);
 ? ? ? ?System.out.println("user = " + user);
 ?  }
}

结果:

total = 2
user = User(id=10, name=范冰冰, age=null, gender=null, note=范冰冰同学在欢哥旁边表演)
user = User(id=8, name=柳岩, age=null, gender=null, note=柳岩同学在欢哥旁边唱歌)


6.5.排序

6.5.1.API介绍

通过SearchSourceBuilder的sort(String, SortOrder)方法用来实现排序条件的封装:


/**
 ?* Adds a sort against the given field name and the sort ordering.
 ?*
 ?* @param name The name of the field,排序字段名称
 ?* @param order The sort ordering,排序的方式
 ?*/
public SearchSourceBuilder sort(String name, SortOrder order) {
 ? ?// ...
}

其中的SortOrder是一个枚举,包含ASC和DESC两个枚举项:


public enum SortOrder implements Writeable {
 ? ?/**
 ? ? * Ascending order.
 ? ? */
 ? ?ASC {
        // ..
 ?  },
 ? ?/**
 ? ? * Descending order.
 ? ? */
 ? ?DESC {
        // ..
 ?  };
 ? ?// ...
}


6.5.2.具体实现

在原由查询的基础上,给SearchSourceBuilder中添加sort即可:


 ? ?//  1.2.添加排序条件
 ? ?sourceBuilder.sort("id", SortOrder.ASC);

完整代码如下:


@Test
public void testBasicSearchAndSort() throws IOException {
 ? ?// 1.创建SearchSourceBuilder对象
 ? ?SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 ? ?//  1.1.添加查询条件QueryBuilders,这里选择match_all,查询所有
 ? ?sourceBuilder.query(QueryBuilders.matchAllQuery());
 ? ?
 ? ?//  1.2.添加排序条件
 ? ?sourceBuilder.sort("id", SortOrder.ASC);
 ? ?
 ? ?// 2.创建SearchRequest对象,并制定索引库名称
 ? ?SearchRequest request = new SearchRequest("user");
 ? ?// 3.添加SearchSourceBuilder对象到SearchRequest对象中
 ? ?request.source(sourceBuilder);
 ? ?// 4.发起请求,得到结果
 ? ?SearchResponse response = client.search(request, RequestOptions.DEFAULT);
 ? ?// 5.解析结果
 ? ?SearchHits searchHits = response.getHits();
 ? ?//  5.1.获取总条数
 ? ?long total = searchHits.getTotalHits().value;
 ? ?System.out.println("total = " + total);
 ? ?//  5.2.获取SearchHits数组,并遍历
 ? ?SearchHit[] hits = searchHits.getHits();
 ? ?for (SearchHit hit : hits) {
 ? ? ? ?//  - 获取其中的`_source`,是JSON数据
 ? ? ? ?String json = hit.getSourceAsString();
 ? ? ? ?//  - 把`_source`反序列化为User对象
 ? ? ? ?User user = JSON.parseObject(json, User.class);
 ? ? ? ?System.out.println("user = " + user);
 ?  }
}


查询结果:


total = 5
user = User(id=2, name=李四, age=21, gender=男, note=李四同学在华为敲代码)
user = User(id=4, name=张伟, age=20, gender=男, note=张伟同学在交友软件谈恋爱)
user = User(id=5, name=李娜, age=28, gender=女, note=李娜同学在欢哥房间学画画)
user = User(id=8, name=柳岩, age=21, gender=女, note=柳岩同学在欢哥旁边唱歌)
user = User(id=10, name=范冰冰, age=25, gender=女, note=范冰冰同学在欢哥旁边表演)


6.5.分页

在原由查询的基础上,给SearchSourceBuilder中添加from和size即可。例如我们的分页信息是:

page = 1,size = 5,代表查询第一页,每页5条,可以计算出: from = (page - 1) * size = 0

所以,代码如下:


// 1.3.添加分页条件
int page = 1, size = 5;
int from = (page - 1) * size;
sourceBuilder.from(from);
sourceBuilder.size(size);

完整代码:


@Test
public void testBasicSearchWithSortAndPage() throws IOException {
 ? ?// 1.创建SearchSourceBuilder对象
 ? ?SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 ? ?//  1.1.添加查询条件QueryBuilders,这里选择match_all,查询所有
 ? ?sourceBuilder.query(QueryBuilders.matchAllQuery());
 ? ?//  1.2.添加排序、分页等其它条件
 ? ?sourceBuilder.sort("id", SortOrder.ASC);
 ? ?// 1.3.添加分页条件
 ? ?int page = 1, size = 5;
 ? ?int from = (page - 1) * size;
 ? ?sourceBuilder.from(from);
 ? ?sourceBuilder.size(size);

 ? ?// 2.创建SearchRequest对象,并制定索引库名称
 ? ?SearchRequest request = new SearchRequest("user");
 ? ?// 3.添加SearchSourceBuilder对象到SearchRequest对象中
 ? ?request.source(sourceBuilder);
 ? ?// 4.发起请求,得到结果
 ? ?SearchResponse response = client.search(request, RequestOptions.DEFAULT);
 ? ?// 5.解析结果
 ? ?SearchHits searchHits = response.getHits();
 ? ?//  5.1.获取总条数
 ? ?long total = searchHits.getTotalHits().value;
 ? ?System.out.println("total = " + total);
 ? ?//  5.2.获取SearchHits数组,并遍历
 ? ?SearchHit[] hits = searchHits.getHits();
 ? ?for (SearchHit hit : hits) {
 ? ? ? ?//  - 获取其中的`_source`,是JSON数据
 ? ? ? ?String json = hit.getSourceAsString();
 ? ? ? ?//  - 把`_source`反序列化为User对象
 ? ? ? ?User user = JSON.parseObject(json, User.class);
 ? ? ? ?System.out.println("user = " + user);
 ?  }
}

结果如下:


total = 5
user = User(id=2, name=李四, age=21, gender=男, note=李四同学在华为敲代码)
user = User(id=4, name=张伟, age=20, gender=男, note=张伟同学在交友软件谈恋爱)
user = User(id=5, name=李娜, age=28, gender=女, note=李娜同学在欢哥房间学画画)
user = User(id=8, name=柳岩, age=21, gender=女, note=柳岩同学在欢哥旁边唱歌)
user = User(id=10, name=范冰冰, age=25, gender=女, note=范冰冰同学在欢哥旁边表演)

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表