引入依赖:
<!--spring boot与es整合依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!--es的java客户端依赖-->
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>7.17.5</version>
</dependency>
<!--s的java客户端需要的jakarta.json依赖-->
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>2.0.1</version>
</dependency>
初始化:
@Data
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "elasticsearch")
public class ElasticSearchConfig {
private String host;
private Integer port;
@Resource
private ObjectMapper objectMapper;
@Bean
public ElasticsearchClient elasticsearchClient() {
log.info("es连接ip:{},端口:{}", host, port);
// 基本的连接
RestClient restClient = RestClient.builder(new HttpHost(host, port)).build();
// 使用自定义json序列化
JacksonJsonpMapper jacksonJsonpMapper = new JacksonJsonpMapper(objectMapper);
// 基于Jackson mapper创建ElasticsearchTransport
ElasticsearchTransport transport = new RestClientTransport(restClient, jacksonJsonpMapper);
// 创建ElasticsearchClient客户端
return new ElasticsearchClient(transport);
}
}
配置文件:
elasticsearch:
host: 192.168.200.102
port: 9200
布尔查询:
查询案例:
@Resource
private ElasticsearchClient elasticsearchClient;
@Test
public void testMatchSearch() throws IOException {
SearchResponse<HotelDoc> response = this.elasticsearchClient.search(builder -> builder
.index("hotel") //指定索引库
//指定查询条件
.query(q -> q.match(m -> m.field("all").query("如家")))
//设置分页查询参数
.from(0)
.size(10),
HotelDoc.class);
//获取命中的数据
HitsMetadata<HotelDoc> hits = response.hits();
System.out.println("数据总数:" + hits.total().value());
hits.hits().forEach(hotelDocHit -> {
System.out.println("得分:"+ hotelDocHit.score());
System.out.println("数据:"+ hotelDocHit.source());
});
}
}
案例:
@Test
public void testRangeSearch() throws IOException {
SearchResponse<HotelDoc> response = this.elasticsearchClient.search(builder -> builder
.index("hotel")
.query(q ->
q.range(r ->
r.field("price")
.gte(JsonData.of("1000"))
.lte(JsonData.of("3000"))
)
),
HotelDoc.class);
//获取命中的数据JsonData
HitsMetadata<HotelDoc> hits = response.hits();
System.out.println("数据总数:" + hits.total().value());
hits.hits().forEach(hotelDocHit -> {
System.out.println("得分:" + hotelDocHit.score());
System.out.println("数据:" + hotelDocHit.source());
});
}
案例:
@Test
public void tesBoolSearch() throws IOException {
//查询杭州的酒店,并且价格500元以下的
SearchResponse<HotelDoc> response = this.elasticsearchClient.search(builder -> builder
.index("hotel")
.query(q ->
q.bool(b ->
b.must(m -> m.term(t -> t.field("city").value("杭州")))
.filter(f ->
f.range(r -> r.field("price")
.lte(JsonData.of(500))))
)
),
HotelDoc.class);
//获取命中的数据JsonData
HitsMetadata<HotelDoc> hits = response.hits();
System.out.println("数据总数:" + hits.total().value());
hits.hits().forEach(hotelDocHit -> {
System.out.println("得分:" + hotelDocHit.score());
System.out.println("数据:" + hotelDocHit.source());
});
}
案例:
@Test
public void testPageAndSort() throws IOException {
// 页码,每页大小
int page = 1, size = 5;
SearchResponse<HotelDoc> response = this.elasticsearchClient.search(builder -> builder
.index("hotel")
.query(q -> q
.matchAll(m -> m)
)
//排序
.sort(s -> s.field(f -> f.field("price").order(SortOrder.Asc)))
//分页
.size(size).from(page),
HotelDoc.class);
//获取命中的数据JsonData
HitsMetadata<HotelDoc> hits = response.hits();
System.out.println("数据总数:" + hits.total().value());
hits.hits().forEach(hotelDocHit -> {
System.out.println("得分:" + hotelDocHit.score());
System.out.println("数据:" + hotelDocHit.source());
});
}
查询:
@Slf4j
@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
@Resource
private ElasticsearchClient elasticsearchClient;
private static final String INDEX_NAME = "hotel";
@Override
public PageResult search(RequestParams params) {
//1. 构造搜索对象
Query.Builder queryBuilder = new Query.Builder();
if (ObjectUtil.isEmpty(params.getKey())) {
//没有搜索关键词
queryBuilder.matchAll(m -> m);
} else {
queryBuilder.match(m -> m.field("all").query(params.getKey()));
}
Query query = queryBuilder.build();
//2. 计算分页参数
int size = params.getSize();
int from = PageUtil.getStart(params.getPage() - 1, size);
try {
//3. 执行搜索
SearchResponse<HotelDoc> response = this.elasticsearchClient.search(builder -> builder
.index(INDEX_NAME) //指定索引库
.query(query) //指定查询条件
.from(from) //设置分页查询参数
.trackScores(true) //返回得分值
.size(size),
HotelDoc.class);
//处理查询结果
HitsMetadata<HotelDoc> hits = response.hits();
//数据列表
List<HotelDoc> hotelDocList = CollStreamUtil.toList(hits.hits(), Hit::source);
return new PageResult(hits.total().value(), hotelDocList);
} catch (Exception e) {
//搜索出现异常
log.error("搜索出现异常!params = {}", params, e);
return new PageResult();
}
}
}
参数封装:
private Query buildBasicQuery(RequestParams params) {
// 1.构建BooleanQuery
BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();
// 2.关键字搜索
if (ObjectUtil.isEmpty(params.getKey())) {
//没有搜索关键词
boolQueryBuilder.must(builder -> builder.matchAll(m -> m));
} else {
boolQueryBuilder.must(builder -> builder.match(m -> m.field("all").query(params.getKey())));
}
// 3.城市条件
if (ObjectUtil.isNotEmpty(params.getCity())) {
boolQueryBuilder.filter(builder -> builder.term(t -> t.field("city").value(params.getCity())));
}
// 4.品牌条件
if (ObjectUtil.isNotEmpty(params.getBrand())) {
boolQueryBuilder.filter(builder -> builder.term(t -> t.field("brand").value(params.getBrand())));
}
// 5.星级条件
if (ObjectUtil.isNotEmpty(params.getStarName())) {
boolQueryBuilder.filter(builder -> builder.term(t -> t.field("starName").value(params.getStarName())));
}
// 6.价格
if (ObjectUtil.isAllNotEmpty(params.getMinPrice(), params.getMaxPrice())) {
boolQueryBuilder.filter(builder -> builder.range(r -> r.field("price")
.gte(JsonData.of(params.getMinPrice())).lte(JsonData.of(params.getMaxPrice()))));
}
// 7.构造Query对象
return new Query.Builder()
.bool(boolQueryBuilder.build())
.build();
}
地理空间查询:
@Override
public PageResult search(RequestParams params) {
//1. 构造搜索对象
Query query = this.buildBasicQuery(params);
//2. 计算分页参数
int size = params.getSize();
int from = PageUtil.getStart(params.getPage() - 1, size);
//模拟位置
params.setLocation("31.03, 121.61");
try {
//构造搜索对象
SearchRequest.Builder searchBuilder = new SearchRequest.Builder();
searchBuilder.index(INDEX_NAME) //指定索引库
.query(query) //指定查询条件
.from(from) //设置分页查询参数
.trackScores(true) //返回得分值
.size(size);
String location = params.getLocation();
if (ObjectUtil.isNotEmpty(location)) {
searchBuilder.sort(s -> s.geoDistance(d -> d.field("location")
.location(GeoLocation.of(geo -> geo.text(location)))
.order(SortOrder.Asc)
.unit(DistanceUnit.Kilometers)));
}
//3. 执行搜索
SearchResponse<HotelDoc> response = this.elasticsearchClient.search(searchBuilder.build(), HotelDoc.class);
//处理查询结果
HitsMetadata<HotelDoc> hits = response.hits();
//数据列表
List<HotelDoc> hotelDocList = CollStreamUtil.toList(hits.hits(), Hit::source);
return new PageResult(hits.total().value(), hotelDocList);
} catch (Exception e) {
//搜索出现异常
log.error("搜索出现异常!params = {}", params, e);
return new PageResult();
}
}