说明

ElasticSearch 使用 6.2.2 版本,Spring Data Elasticsearch 使用 3.1.3,Spring Framework使用 5.1.19

Spring Data Release Train Spring Data Elasticsearch Elasticsearch Spring Framework Spring Boot
2021.0 (Pascal)[1] 4.2.x[1] 7.12.0 5.3.x[1] 2.4.x[1]
2020.0 (Ockham) 4.1.x 7.9.3 5.3.2 2.4.x
Neumann 4.0.x 7.6.2 5.2.12 2.3.x
Moore 3.2.x 6.8.12 5.2.12 2.2.x
Lovelace[2] 3.1.x[2] 6.2.2 5.1.19 2.1.x
Kay[2] 3.0.x[2] 5.5.0 5.0.13 2.0.x
Ingalls[2] 2.1.x[2] 2.4.0 4.3.25 1.5.x

环境

elasticsearch-6.2.2、elasticsearch-analysis-ik-6.2.2、kibana-6.2.2-windows-x86_64、

Chrome 浏览器、ElasticSearch-Head_v0.1.5.crx插件

pom.xml

引入 elasticsearch 和 Spring Data Elasticsearch 资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.2.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.2.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>3.1.3.RELEASE</version>
</dependency>

spring.xml

1
<import resource="classpath:spring-elastic.xml"/>

spring-elastic.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="com.bjtcrj.scm.resource.elastic" />

<!-- 必须指向存放repository文件的包 -->
<elasticsearch:repositories base-package="com.bjtcrj.scm.resource.elastic.repository" />

<!-- 配置Client -->
<elasticsearch:transport-client id="client" cluster-nodes="10.211.55.3:9300" cluster-name="docker-cluster"/>

<!-- 配置搜索模板 -->
<bean id="elasticsearchTemplate"
class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client" />
</bean>
</beans>

Geosystem.java-索引对象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.bjtcrj.scm.resource.elastic.repository;

import com.bjtcrj.scm.common.utils.Constants;
import lombok.Data;
import org.springframework.data.annotation.Id;
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.Date;

@Data
@Document(indexName = Constants.GEOSYSTEM_INDEXNAME, type = "doc")
public class Geosystem implements Serializable {
private static final long serialVersionUID = 1L;

/**
* 索引 ID
*/
@Id
@Field(index=true, store = true, type = FieldType.Long)
private Long id;

/**
* 信息类型:
* 0- 城市部件表 SCM_CITYCOMPONENT
* 1- 区域地名表 SCM_AREANAME
* 2- 地片或小区地名表 SCM_COMMUNITYNAME
* 3- 门(楼)牌地址表 SCM_HOUSEADDRESS
* 4- 门(楼)牌表 SCM_HOUSENUMBER
* 5- 标志物表 SCM_MARKER
* 6- 标志物地址表 SCM_MARKERADDRESS
* 7- 兴趣点地址表 SCM_POINTADDRESS
* 8- 兴趣点表 SCM_POINT
*/
@Field(index=true, store = true, type = FieldType.Long)
private Integer type;

/**
* 信息 ID
*/
@Field(index=true, store = true, type = FieldType.Keyword)
private String infoId;

@Field(index=true, store = true, type = FieldType.Keyword)
private String point;

@Field(index = true, store = true, type = FieldType.Date)
private Date createTime;

@Field(index = true, analyzer = "ik_max_word", store = true, searchAnalyzer = "ik_smart", type = FieldType.Text)
private String fullText;

public Geosystem() {
}

public Geosystem(long id, Integer type, String infoId, String point, String fullText) {
this.id = id;
this.type = type;
this.infoId = infoId;
this.point = point;
this.createTime = new Date();
this.fullText = fullText;
}
}

GeosystemRepository.java

1
2
3
4
5
6
7
8
9
package com.bjtcrj.scm.resource.elastic.repository;

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface GeosystemRepository extends ElasticsearchRepository<Geosystem, Long> {

}

GeosystemService.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.bjtcrj.scm.resource.elastic.service;

import com.bjtcrj.scm.resource.elastic.repository.Geosystem;
import org.springframework.data.domain.Page;

public interface GeosystemService {
boolean indexExists();
boolean createIndex();
boolean deleteIndex();
String init();
Page<Geosystem> search(String key, int page, int size);
}

GeosystemServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package com.bjtcrj.scm.resource.elastic.service.impl;

import com.bjtcrj.scm.common.utils.Constants;
import com.bjtcrj.scm.common.utils.SnowFlakeID;
import com.bjtcrj.scm.resource.elastic.repository.Geosystem;
import com.bjtcrj.scm.resource.elastic.repository.GeosystemRepository;
import com.bjtcrj.scm.resource.elastic.service.GeosystemService;
import com.bjtcrj.scm.resource.persistence.dao.*;
import com.bjtcrj.scm.resource.persistence.pojo.*;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service("geosystemService")
public class GeosystemServiceImpl implements GeosystemService {
@Autowired
private GeosystemRepository geosystemRepository;

@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Resource
private CitycomponentDao citycomponentDao;

//批量值
public static final int BATCH_SIZE = 50000;

@Override
public String init() {
//存在先删除
if (indexExists()) {
if(deleteIndex()) {
log.info("删除索引库"+Constants.GEOSYSTEM_INDEXNAME+"成功!");
} else {
log.info("删除索引库"+Constants.GEOSYSTEM_INDEXNAME+"失败!");
}

//创建索引
if(createIndex()) {
log.info("创建索引"+Constants.GEOSYSTEM_INDEXNAME+"成功!");
} else {
log.info("创建索引"+Constants.GEOSYSTEM_INDEXNAME+"失败!");
}
}

StringBuilder ret = new StringBuilder();
//城市部件表 SCM_CITYCOMPONENT
int citycomponent = saveCitycomponent();
ret.append("添加城市部件:"+citycomponent+"条;");

return ret.toString();
}

//城市部件表 SCM_CITYCOMPONENT
private int saveCitycomponent() {
List<Geosystem> data;
int start;
int end;
int total = this.citycomponentDao.selectAllCount();
Map<String, Integer> map = new HashMap<>();
int size = total/ BATCH_SIZE + 1; //批量操作次数
List<Citycomponent> citycomponentList = null;
for (int i = 0; i < size; i++) {
start = i* BATCH_SIZE;
end = (i+1)* BATCH_SIZE;
map.put("start", start);
map.put("end", end);
citycomponentList = this.citycomponentDao.selectByPage(map);

if(citycomponentList != null && citycomponentList.size() > 0) {
data = new ArrayList<>(citycomponentList.size());
for (Citycomponent citycomponent : citycomponentList) {
data.add(new Geosystem(SnowFlakeID.getId(), Constants.GEOSYSTEM_INFOTYPE_0, citycomponent.getCcid(), citycomponent.getGeosupermap(), citycomponent.getFullText()));
}

//插入数据到索引库
geosystemRepository.saveAll(data);
}
}
return total;
}

@Override
public Page<Geosystem> search(String key, int page, int size) {
// 构造查询条件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加基本的分词条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery("fullText", key));
queryBuilder.withQuery(boolQueryBuilder);

// 排序条件
// queryBuilder.withSort(SortBuilders.fieldSort("_id").order(SortOrder.ASC));

// 分页条件
queryBuilder.withPageable(PageRequest.of(page, size));
return geosystemRepository.search(queryBuilder.build());
}

/**
* 索引是否存在
*/
@Override
public boolean indexExists() {
return elasticsearchTemplate.indexExists(Geosystem.class);
}

/**
* 创建索引
* @return
*/
@Override
public boolean createIndex() {
// 创建索引,会根据Item类的@Document注解信息来创建
boolean index = elasticsearchTemplate.createIndex(Geosystem.class);

// 配置映射,会根据Item类中的id、Field等字段来自动完成映射
boolean b = elasticsearchTemplate.putMapping(Geosystem.class);

return index && b;
}

/**
* 删除 index
*/
@Override
public boolean deleteIndex() {
return elasticsearchTemplate.deleteIndex(Geosystem.class);
}
}

GeosystemController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package com.bjtcrj.scm.resource.controller;

import com.bjtcrj.scm.common.utils.Json;
import com.bjtcrj.scm.resource.elastic.repository.Geosystem;
import com.bjtcrj.scm.resource.elastic.service.GeosystemService;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/geosystem")
@Slf4j
public class GeosystemController {

@Autowired
private GeosystemService geosystemService;

/**
* 索引库是否存在
* @return
*/
@RequestMapping("/indexExists")
public Json indexExists() {
Json json = new Json();
json.setSuccess(geosystemService.indexExists());
return json;
}

/**
* 创建索引库
* @return
*/
@RequestMapping("/createIndex")
public Json createIndex() {
Json json = new Json();
boolean index = geosystemService.createIndex();
if(index) {
json.setMsg("创建成功!");
} else {
json.setMsg("创建失败!");
}
json.setSuccess(index);
return json;
}

/**
* 删除索引库
* @return
*/
@RequestMapping("/deleteIndex")
public Json deleteIndex() {
Json json = new Json();
boolean index = geosystemService.deleteIndex();
if(index) {
json.setMsg("删除成功!");
} else {
json.setMsg("删除失败!");
}
json.setSuccess(index);
return json;
}

/**
* 初始化数据
* @return
*/
@RequestMapping("/init")
public Json init() {
Json json = new Json();
json.setMsg(geosystemService.init());
return json;
}

@RequestMapping("/search")
public Json search(String key, Integer page, Integer size) {
Json json = new Json();
if (StringUtil.isNullOrEmpty(key)) {
json.setSuccess(false);
json.setMsg("请输入关键词");
return json;
}
if (page == null || size == null) {
json.setSuccess(false);
json.setMsg("分页条件不能为空");
return json;
}

Page<Geosystem> result = geosystemService.search(key, page, size);
json.setSuccess(true);
json.setObj(result);
return json;
}
}