- 引入pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
- application.yml 添加es的相關配置
spring:
data:
elasticsearch:
cluster-nodes: localhost:9300
cluster-name: es_cluster
- 創建實體類,
- 中文分詞,需要設置
@Document
裏面的 type = "article"
,在對應的字段上添加@Field(analyzer = "ik_max_word", searchAnalyzer = "ik_max_word", type = FieldType.Text)
註解
- 根據地理位置排序,需要添加
@GeoPointField
註解GeoPoint
類型的對象
@Data
@Document(indexName = "address", type = "article")
public class Address implements Serializable {
@Id
private String id;
@Field(analyzer = "ik_max_word", searchAnalyzer = "ik_max_word", type = FieldType.Text)
private String location;
@GeoPointField
private GeoPoint geoPoint;
private String geo;
public GeoPoint getGeoPoint(){
String[] split = geo.split(",");
return new GeoPoint(Double.parseDouble(split[0]),Double.parseDouble(split[1]));
}
}
- elasticsearch常用的一些操作
@Test
public void save() {
Address address = new Address();
address.setId(UUID.randomUUID().toString());
address.setLocation("崑山市前進西路1801號");
address.setGeo("31.386311,120.916435");
addressDocumentRepository.save(address);
}
@Test
public void saveAll() throws IOException {
File geo = ResourceUtils.getFile("classpath:geo.json");
String content = new String(Files.readAllBytes(geo.toPath()));
List<Address> list = JSONUtil.toList(JSONUtil.parseArray(content), Address.class);
addressDocumentRepository.saveAll(list);
}
@Test
public void findAll() {
Iterable<Address> all = addressDocumentRepository.findAll();
for (Address address : all) {
System.out.println(JSONUtil.toJsonStr(address));
}
}
@Test
public void page() {
BoolQueryBuilder qb = QueryBuilders.boolQuery();
qb.must(QueryBuilders.termQuery("location", "周莊"));
Pageable pageable = PageRequest.of(0, 5);
Page<Address> search = addressDocumentRepository.search(qb, pageable);
System.out.println("==" + search.getTotalElements());
System.out.println("==" + search.getTotalPages());
search.getContent().forEach(address -> System.out.println(JSONUtil.toJsonStr(address)));
}
@Test
public void ikSearch() {
String searchField = "location";
QueryBuilder matchQuery = QueryBuilders.boolQuery()
.must(QueryBuilders.multiMatchQuery("崑山", searchField).analyzer("ik_max_word")
.operator(Operator.OR));
int pageNo = 1;
int pageSize = 10;
HighlightBuilder highlightBuilder = createHighlightBuilder(searchField);
SearchResponse response = elasticsearchTemplate.getClient().prepareSearch("address")
.setQuery(matchQuery)
.highlighter(highlightBuilder)
.setFrom((pageNo - 1) * pageSize)
.setSize(pageNo * pageSize)
.get();
SearchHits hits = response.getHits();
List<Address> hitList = getHitList(hits);
System.out.println(hits.getTotalHits());
hitList.forEach(address -> {
System.out.println(JSONUtil.toJsonStr(address));
});
}
private HighlightBuilder createHighlightBuilder(String... fieldNames) {
HighlightBuilder highlightBuilder = new HighlightBuilder()
.preTags("<span style='color:red'>")
.postTags("</span>");
for (String fieldName : fieldNames) {
highlightBuilder.field(fieldName);
}
return highlightBuilder;
}
private List<Address> getHitList(SearchHits hits) {
List<Map<String, Object>> list = new ArrayList<>();
Map<String, Object> map;
for (SearchHit searchHit : hits) {
map = new HashMap<>(searchHit.getSourceAsMap());
Map<String, Object> hitMap = new HashMap<>();
searchHit.getHighlightFields().forEach((k, v) -> {
StringBuilder high = new StringBuilder();
for (Text text : v.getFragments()) {
high.append(text.string());
}
hitMap.put(v.getName(), high.toString());
});
map.putAll(hitMap);
list.add(map);
}
return JSON.parseArray(JSON.toJSONString(list), Address.class);
}
@Test
public void sortByLocation() {
Pageable pageable = PageRequest.of(0, 20);
GeoDistanceQueryBuilder geoBuilder = new GeoDistanceQueryBuilder("geoPoint");
geoBuilder.point(31.186245, 121.037991);
geoBuilder.distance(100, DistanceUnit.KILOMETERS);
GeoDistanceSortBuilder sortBuilder = new GeoDistanceSortBuilder("geoPoint", 31.186245, 121.037991);
sortBuilder.order(SortOrder.ASC);
sortBuilder.unit(DistanceUnit.METERS);
NativeSearchQueryBuilder qb = new NativeSearchQueryBuilder()
.withPageable(pageable)
.withFilter(geoBuilder)
.withSort(sortBuilder);
Page<Address> page = addressDocumentRepository.search(qb.build());
List<Address> list = page.getContent();
list.forEach(l -> {
double calculate = GeoDistance.PLANE.calculate(l.getGeoPoint().getLat(), l.getGeoPoint().getLon(), 31.186245, 121.037991, DistanceUnit.METERS);
System.out.println(JSONUtil.toJsonStr(l));
System.out.println("距離" + (int) calculate + "m");
});
}
@Test
public void delIndex() {
elasticsearchTemplate.deleteIndex("address");
}
@Test
public void deleteAll() {
addressDocumentRepository.deleteAll();
}
@Test
public void test2() throws IOException {
String fileName = "geo.json";
ClassLoader classLoader = EsTest.class.getClassLoader();
File file = new File(Objects.requireNonNull(classLoader.getResource(fileName)).getFile());
String content = new String(Files.readAllBytes(file.toPath()));
System.out.println(content);
}
@Test
public void test1() throws IOException {
File geo = ResourceUtils.getFile("classpath:geo.json");
String content = new String(Files.readAllBytes(geo.toPath()));
System.out.println(content);
}
- 問題總結
在多模塊情況下,會掃描不到bean,需要添加一個註解
@EnableElasticsearchRepositories(basePackages = "com.good.xxx.xxx")
文章用到的項目源碼地址