SpringBoot项目中进行Elasticsearch的多层嵌套搜索查询,
这里通过省市区示例进行演示:
目前存放的数据是:
{
"_index": "province_info",
"_type": "_doc",
"_id": "1",
"_version": 1,
"_score": 0,
"_source": {
"_class": "com.etc.ec.share.api.entity.es.order.ProvinceInfoEntity",
"provinceName": "江苏省",
"provinceCode": "05",
"cityInfos": [
{
"id": 102,
"cityName": "苏州市",
"cityCode": "102"
},
{
"id": 0,
"districtInfos": [
{
"id": 1001,
"districtName": "姑苏区",
"districtCode": "1001"
},
{
"id": 1002,
"districtName": "工业园区",
"districtCode": "1002"
}
]
}
],
"id": 1
}
}
首先定义索引结构
一种是通过Postman工具或Kibana界面来进行API创建;
另一种是通过SpringBoot的@Document注解声明实体类方式(默认是自动创建索引但是不会设置setting);
@Document源码:
// 默认true,自动创建索引
boolean createIndex() default true;
Elasticsearch实体结构:
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.io.Serializable;
import java.util.List;
/**
* created by etc.
*
* @author: xxxx
* @date: 2022/5/18
* @description: 省市区
*/
@Document(indexName = "province_info", shards = 5, replicas = 1)
@Data
@NoArgsConstructor
@SuperBuilder
public class ProvinceEntity {
/**
* id
*/
@Field(type = FieldType.Long)
private long id;
/**
* 省名称
*/
@Field(type = FieldType.Keyword)
private String provinceName;
/**
* 省编码
*/
@Field(type = FieldType.Keyword)
private String provinceCode;
/**
* 市信息
*/
@Field(type = FieldType.Nested)
private List cityInfos;
@Builder
@Data
public static class CityInfo implements Serializable {
/**
* id
*/
@Field(type = FieldType.Long)
private long id;
/**
* 市名称
*/
@Field(type = FieldType.Keyword)
private String cityName;
/**
* 市编码
*/
@Field(type = FieldType.Keyword)
private String cityCode;
/**
* 区信息
*/
@Field(type = FieldType.Nested)
private List districtInfos;
@Builder
@Data
public static class DistrictInfo implements Serializable {
/**
* id
*/
@Field(type = FieldType.Long)
private long id;
/**
* 区名称
*/
@Field(type = FieldType.Keyword)
private String districtName;
/**
* 区编码
*/
@Field(type = FieldType.Keyword)
private String districtCode;
}
}
}
json格式:
{
"cityInfos": [
{
"cityCode": "",
"cityName": "",
"districtInfos": [
{
"districtCode": "",
"districtName": "",
"id": 0
}
],
"id": 0
}
],
"id": 0,
"provinceCode": "",
"provinceName": ""
}
写入数据
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Test
public void testInsertDocument(){
ProvinceInfoEntity provinceInfoEntity = ProvinceInfoEntity.builder().build();
provinceInfoEntity.setId(1L);
provinceInfoEntity.setProvinceCode("05");
provinceInfoEntity.setProvinceName("江苏省");
ProvinceInfoEntity.CityInfo cityInfo1 = ProvinceInfoEntity.CityInfo.builder().build();
cityInfo1.setCityCode("101");
cityInfo1.setCityName("南京市");
cityInfo1.setId(101);
ProvinceInfoEntity.CityInfo cityInfo2 = ProvinceInfoEntity.CityInfo.builder().build();
cityInfo2.setCityCode("102");
cityInfo2.setCityName("苏州市");
cityInfo2.setId(102);
ProvinceInfoEntity.CityInfo.DistrictInfo districtInfo1 = ProvinceInfoEntity.CityInfo.DistrictInfo.builder().build();
ProvinceInfoEntity.CityInfo.DistrictInfo districtInfo2 = ProvinceInfoEntity.CityInfo.DistrictInfo.builder().build();
ProvinceInfoEntity.CityInfo.DistrictInfo districtInfo3 = ProvinceInfoEntity.CityInfo.DistrictInfo.builder().build();
ProvinceInfoEntity.CityInfo.DistrictInfo districtInfo4 = ProvinceInfoEntity.CityInfo.DistrictInfo.builder().build();
List districtInfos = new ArrayList<>();
List districtInfos1 = new ArrayList<>();
districtInfo1.setId(1001);
districtInfo1.setDistrictName("工业园区");
districtInfo1.setDistrictCode("1001");
districtInfo2.setId(1002);
districtInfo2.setDistrictName("相城区");
districtInfo2.setDistrictCode("1002");
districtInfo3.setId(1003);
districtInfo3.setDistrictName("姑苏区");
districtInfo3.setDistrictCode("1003");
districtInfos.add(districtInfo1);
districtInfos.add(districtInfo2);
districtInfos.add(districtInfo3);
districtInfo4.setDistrictCode("10");
districtInfo4.setDistrictName("鼓楼区");
districtInfos1.add(districtInfo4);
cityInfo1.setDistrictInfos(districtInfos1);
cityInfo2.setDistrictInfos(districtInfos);
List cityInfos = new ArrayList<>();
cityInfos.add(cityInfo1);
cityInfos.add(cityInfo2);
provinceInfoEntity.setCityInfos(cityInfos);
elasticsearchRestTemplate.save(provinceInfoEntity);
}
嵌套搜索查询
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Test
public void testSearch(){
QueryBuilder provinceItemsQuery = QueryBuilders.nestedQuery("cityInfos.districtInfos",
QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("cityInfos.districtInfos.districtName", "工业园区"))
.should(QueryBuilders.matchQuery("cityInfos.districtInfos.districtCode", "工业园区")),
ScoreMode.Total);
//构建分页
NativeSearchQueryBuilder builder=new NativeSearchQueryBuilder();
NativeSearchQuery query=builder.withQuery(provinceItemsQuery)
.build();
SearchHits search = elasticsearchRestTemplate.search(query, ProvinceInfoEntity.class);
Stream> searchHitStream = search.get();
}
传送门:
Elasticsearch多层级嵌套模糊搜索高亮关键词实现
-------------欢迎各位留言交流,如有不正确的地方,请予以指正。【Q:981233589】