在上一篇我们已经创建好了索引库,并将采集到的数据添加了进去,今天我们学习 Spring Boot 和 Elasticsearch 整合以后如何查询数据。
1、构造查询条件
查询条件的构造还是使用 Elasticsearch Java High Level REST Client 相关的 API,不了解的可以参考Elasticsearch 使用 Java High Level REST Client 查询文档。
如下,我们的查询条件是author
或者name
包含指定的关键字,并且commentCount
数量大于等于10:
BoolQueryBuilder keywordQueryBuilder = QueryBuilders.boolQuery()
.should(QueryBuilders.matchPhraseQuery("author", keyword))
.should(QueryBuilders.matchPhraseQuery("name", keyword));
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.must(keywordQueryBuilder)
.must(QueryBuilders.rangeQuery("commentCount").gte(10));
2、NativeSearchQueryBuilder
上边虽然构造好了查询条件,但不能直接使用。无论我们使用ElasticsearchRestTemplate
取查询,还是使用ElasticsearchRepository
去查询,都需要一个Query
类型的参数。我们通常会使用NativeSearchQueryBuilder
来创建一个Query
类型的参数NativeSearchQuery
:
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().build();
我们可以使用NativeSearchQueryBuilder
来接收上边构造的查询条件:
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder)
.build()
除此之外,还可以使用NativeSearchQueryBuilder
来配置其它的查询设置,例如:
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder)
// 分页
.withPageable(PageRequest.of(pageNum - 1, pageSize))
// 指定查询结果包含那些文档字段
.withFields("author", "name", "price", "commentCount")
// 查询结果如何排序
.withSort(new FieldSortBuilder("price").order(SortOrder.ASC))
// 设置查询结果高亮
.withHighlightBuilder(highlightBuilder)
// 添加聚合查询
.addAggregation(priceAvgAggregation)
.build();
3、查询
如下,我们写一个综合的查询例子,根据输入的关键字查询书籍:
@Service
public class BookService {
@Autowired
ElasticsearchRestTemplate elasticsearchRestTemplate;
/**
* @param keyword 关键字
* @param pageNum 页码从1开始
* @param pageSize 每页数据条数
*/
public List<Book> queryBook(String keyword, int pageNum, int pageSize) {
BoolQueryBuilder keywordQueryBuilder = QueryBuilders.boolQuery()
.should(QueryBuilders.matchPhraseQuery("author", keyword))
.should(QueryBuilders.matchPhraseQuery("name", keyword));
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.must(keywordQueryBuilder)
.must(QueryBuilders.rangeQuery("commentCount").gte(10));
HighlightBuilder highlightBuilder = new HighlightBuilder()
.field("author").field("name")
.preTags("<span style='color:red'>")
.postTags("</span>")
// 如果要高亮显示的字段内容很多,需要如下配置,避免高亮显示不全、内容缺失
.fragmentSize(1000) // 最大高亮分片数
.numOfFragments(0);// 从第一个分片获取高亮片段
AvgAggregationBuilder priceAvgAggregation = AggregationBuilders.avg("avgPrice").field("price");
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder)
.withPageable(PageRequest.of(pageNum - 1, pageSize))
.withFields("author", "name", "price", "commentCount")
.withSort(new FieldSortBuilder("price").order(SortOrder.ASC))
.withHighlightBuilder(highlightBuilder)
.addAggregation(priceAvgAggregation)
.build();
// 开始查询
SearchHits<Book> search = elasticsearchRestTemplate.search(nativeSearchQuery, Book.class);
long totalHits = search.getTotalHits();
long totalPage = (totalHits % pageSize == 0) ? totalHits / pageSize : totalHits / pageSize + 1;
System.out.println("总数据条数:" + totalHits);
System.out.println("总页数:" + totalPage);
System.out.println("当前页码:" + pageNum);
double avgPrice = ((Avg) search.getAggregations().get("avgPrice")).getValue();
System.out.println("搜索到的书籍均价:" + avgPrice);
List<Book> resultList = new ArrayList<>();
// 解析查询结果
for (SearchHit<Book> searchHit : search.getSearchHits()) {
Book book = searchHit.getContent();
if (searchHit.getHighlightFields().containsKey("author")) {
// 提取高亮字段
book.setAuthor(searchHit.getHighlightFields().get("author").get(0));
}
if (searchHit.getHighlightFields().containsKey("name")) {
// 提取高亮字段
book.setName(searchHit.getHighlightFields().get("name").get(0));
}
resultList.add(book);
System.out.println(JSONObject.toJSONString(book));
}
return resultList;
}
}
这里我们使用的是ElasticsearchRestTemplate
的search()
方法去查询,其实它还提供了一些的query()
方法,但是基本都过时了,可以用search()
系列的方法来代替。同时ElasticsearchRepository
查询相关的方法基本也都过时了,所以使用ElasticsearchRestTemplate
的search()
系列方法去查询是目前比较好的选择。
如下我们尝试查询一下:
@RunWith(SpringRunner.class)
@SpringBootTest
class LearnElasticsearchApplicationTests {
@Autowired
BookService bookService;
@Test
void testES() throws IOException {
bookService.queryBook("刘慈欣", 1, 10);
}
}
查询的结果如下:
除了上边复杂的查询,也可以直接根据文档 id,查询:
public Book queryBookById(String id) {
Book book = elasticsearchRestTemplate.get(id, Book.class);
System.out.println(JSONObject.toJSONString(book));
return book;
}
关于聚合查询的内容就不展开讲了,就是使用 Java High Level REST Client 的相关 API,具体可以参考Elasticsearch 使用 Java High Level REST Client 聚合查询。
本文详细的代码可以参考:https://github.com/SheHuan/LearnElasticsearch
网友评论