Elasticsearch可以通过对doc文档的操作实现对不同条件下的搜索,排序,打分等等功能,这个功能不仅可以用dsl语句在控制台的里实现,也可以使用springboot提供的api用java代码实现。
1 事先准备
1.1导入相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
1.2配置环境
spring:
elasticsearch:
rest:
uris: 192.168.184.100:9200 #输入你部署好的es服务地址
data:
elasticsearch:
repositories:
enabled: true
为了在后面代码中更好使用es工具,我们通过配置类将RestHighLevelClient添加到spring容器中管理。
@Value("${spring.elasticsearch.rest.uris}")
private String uris;
@Bean
public RestHighLevelClient elasticsearchClient() {
ClientConfiguration configuration = ClientConfiguration.builder()
.connectedTo(uris)
.build();
return RestClients.create(configuration).rest();
}
2 代码编写
2.1查询所有
@Test
public void MatchAllTest() throws IOException {
//构建查询request对象
SearchRequest searchRequest = new SearchRequest("hotel1");
//查询条件
searchRequest.source().query(QueryBuilders.matchAllQuery());
//发起查询
SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//结果展示
showRes(res);
}
我将结果处理抽取出来进行单独处理
public void showRes(SearchResponse res){
SearchHits hits = res.getHits();
int length = (int) hits.getTotalHits().value;
System.out.println("共查询到 "+length+" 条数据");
//获取所有查询数据
SearchHit[] hits1 = hits.getHits();
for (SearchHit documentFields : hits1) {
//将doc转为Object对象
String sourceAsString = documentFields.getSourceAsString();
Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
HotelDoc hotelDoc = JSON.parseObject(sourceAsString, HotelDoc.class);
//高亮显示搜索内容
if(!CollectionUtils.isEmpty(highlightFields)){
HighlightField highlightField = highlightFields.get("name");
Text[] fragments = highlightField.getFragments();
String s = fragments[0].toString();
hotelDoc.setName(s);
}
System.out.println(hotelDoc);
}
}
其他查询也都大差不差,这里全部贴上代码:
/**
* match模糊匹配
* @throws IOException
*/
@Test
public void MatchTest() throws IOException {
//构建查询request对象
SearchRequest searchRequest = new SearchRequest("hotel1");
//查询条件
searchRequest.source().query(QueryBuilders.matchQuery("name","如家"));
//发起查询
SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//结果展示
showRes(res);
}
/**
* multi_match 会匹配多个字段信
* @throws IOException
*/
@Test
public void MultiMatchTest() throws IOException {
//构建查询request对象
SearchRequest searchRequest = new SearchRequest("hotel1");
//查询条件
searchRequest.source().query(QueryBuilders.multiMatchQuery("外滩如家酒店","brand","name","business"));
//发起查询
SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//结果展示
showRes(res);
}
/**
* term精确查询,必须与传入的值完全相同才能匹配成功
* @throws IOException
*/
@Test
public void TermTest() throws IOException {
//构建查询request对象
SearchRequest searchRequest = new SearchRequest("hotel1");
//查询条件
searchRequest.source().query(QueryBuilders.termQuery("id","434082"));
//发起查询
SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//结果展示
showRes(res);
}
/**
* range范围查询
* @throws IOException
*/
@Test
public void rangeTest() throws IOException {
//构建查询request对象
SearchRequest searchRequest = new SearchRequest("hotel1");
//查询条件
searchRequest.source().query(QueryBuilders.rangeQuery("score").gt(10).lt(30));
//发起查询
SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//结果展示
showRes(res);
}
//distance查询地理位置
@Test
public void distanceTest() throws IOException {
//构建查询request对象
SearchRequest searchRequest = new SearchRequest("hotel1");
//查询条件
searchRequest.source().query(QueryBuilders
.geoDistanceQuery("location") //具体根据什么信息查询
.distance("3km") //查询范围
.point(31.220706,121.498769)); //范围中心坐标
//发起查询
SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//结果展示
showRes(res);
}
//复合查询 boolean
@Test
public void boolTest() throws IOException {
//构建查询request对象
SearchRequest searchRequest = new SearchRequest("hotel1");
//查询条件
searchRequest.source().query(QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("name","如家"))
.filter(QueryBuilders.rangeQuery("price").lt(300))
.should(QueryBuilders.termQuery("city","北京"))
);
//发起查询
SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//结果展示
showRes(res);
}
//排序和分页
@Test
public void SortAndPageTest() throws IOException {
int page = 1;int size = 5;
//构建查询request对象
SearchRequest searchRequest = new SearchRequest("hotel1");
//查询条件
searchRequest.source().query(QueryBuilders.matchAllQuery());
searchRequest.source().size(size).from((page-1)*size);
searchRequest.source().sort("price", SortOrder.ASC);
//发起查询
SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//结果展示
showRes(res);
}
/**
* 高亮搜索内容
* @throws IOException
*/
@Test
public void HighlightTest() throws IOException {
//构建查询request对象
SearchRequest searchRequest = new SearchRequest("hotel1");
//查询条件
searchRequest.source().query(QueryBuilders.matchQuery("all","如家酒店"));
searchRequest.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
//发起查询
SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//结果展示
showRes(res);
}
对结果相关度算分后重新排序这个稍微复杂点,单独列出来:
/**
* 根据相关度算分排序
* @throws IOException
*/
@Test
public void functionScoreTest() throws IOException {
//构建查询request对象
SearchRequest searchRequest = new SearchRequest("hotel1");
//基础查询条件
MatchAllQueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();
//算分查询
FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(
matchAllQuery, //基础查询
new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ //算分函数
new FunctionScoreQueryBuilder.FilterFunctionBuilder(
QueryBuilders.termQuery("isAD",true), //筛选算分条件
ScoreFunctionBuilders.weightFactorFunction(10) //算分方式
)
}).boostMode(CombineFunction.SUM); //对是广告的查询结果加10分
//查询条件
searchRequest.source().query(functionScoreQuery);
//发起查询
SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//结果展示
showRes(res);
}