赞
踩
需求:实现在对数据库查询时,同时更新ES服务中指定索引的数据。若用户重建数据库,则需删除旧索引,查询数据库新数据,而后插入指定新索引中。
创建索引之前,进行数据操作部分(操作数据过程中同时更新当前索引数据):
点击重建索引按钮之后,进行对数据检索部分:
elasticsearch:7.16.3
spring-boot-starter-parent:2.3.0.RELEASE
当运行之后输入http://localhost:9200/
如果有返回值则说明安装成功
- <!--全文检索-->
- <!--添加springboot-elasticsearch依赖-->
- <!--es客户端,不使用springboot封装的客户端-->
- <dependency>
- <groupId>org.elasticsearch.client</groupId>
- <artifactId>elasticsearch-rest-high-level-client</artifactId>
- <version>7.5.2</version>
- </dependency>
- <dependency>
- <groupId>org.elasticsearch</groupId>
- <artifactId>elasticsearch</artifactId>
- <version>7.5.2</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
- </dependency>
- <dependency>
- <groupId>org.elasticsearch.client</groupId>
- <artifactId>elasticsearch-rest-client</artifactId>
- <version>7.6.2</version>
- </dependency>
application.yml中的配置如下:
- elasticsearch:
- schema: http
- address: 127.0.0.1:9200
- connectTimeout: 5000
- socketTimeout: 5000
- connectionRequestTimeout: 5000
- maxConnectNum: 100
- maxConnectPerRoute: 100
全文检索模块后端接口结构:
- /**
- * @Deacription ElasticSearch 配置
- * @Author hmf
- * @Date 2022/8/29
- * @Version 1.0
- **/
- @Configuration
- public class ElasticSearchConfiguration {
- /** 协议 */
- @Value("${elasticsearch.schema:http}")
- private String schema;
-
- /** 集群地址,如果有多个用“,”隔开 */
- @Value("${elasticsearch.address}")
- private String address;
-
- /** 连接超时时间 */
- @Value("${elasticsearch.connectTimeout}")
- private int connectTimeout;
-
- /** Socket 连接超时时间 */
- @Value("${elasticsearch.socketTimeout}")
- private int socketTimeout;
-
- /** 获取连接的超时时间 */
- @Value("${elasticsearch.connectionRequestTimeout}")
- private int connectionRequestTimeout;
-
- /** 最大连接数 */
- @Value("${elasticsearch.maxConnectNum}")
- private int maxConnectNum;
-
- /** 最大路由连接数 */
- @Value("${elasticsearch.maxConnectPerRoute}")
- private int maxConnectPerRoute;
-
- @Bean(name = "restHighLevelClient")
- public RestHighLevelClient restHighLevelClient() {
- // 拆分地址
- List<HttpHost> hostLists = new ArrayList<>();
- String[] hostList = address.split(",");
- for (String addr : hostList) {
- String host = addr.split(":")[0];
- String port = addr.split(":")[1];
- hostLists.add(new HttpHost(host, Integer.parseInt(port), schema));
- }
- // 转换成 HttpHost 数组
- HttpHost[] httpHost = hostLists.toArray(new HttpHost[]{});
- // 构建连接对象
- RestClientBuilder builder = RestClient.builder(httpHost);
- // 异步连接延时配置
- builder.setRequestConfigCallback(requestConfigBuilder -> {
- requestConfigBuilder.setConnectTimeout(connectTimeout);
- requestConfigBuilder.setSocketTimeout(socketTimeout);
- requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
- return requestConfigBuilder;
- });
- // 异步连接数配置
- builder.setHttpClientConfigCallback(httpClientBuilder -> {
- httpClientBuilder.setMaxConnTotal(maxConnectNum);
- httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
- return httpClientBuilder;
- });
- return new RestHighLevelClient(builder);
- }
-
-
- }
其中Document必须提前设置好指定存入的index(可以理解成数据库的某个表)
- /**
- * @author hmf
- * @create 2022-08-29 10:28
- */
-
- @Data
- @Document(indexName = "gt_office_doc", type = "_doc")
- public class OfficeDocVO {
-
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String officeDocFileId;
- @JSONField(serialize = false)
- private MultipartFile docFileContent;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String docFileName;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String docFileKeyword;
- @Id
- private String officeDocId;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String docTitle;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String dispatchnoId;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String issuingAuthority;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String issuingAuthorityYear;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String postingSequenceNumber;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String orgUuid;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String orgName;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String drafterId;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String drafterName;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String uploaderName;
- @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
- private Date draftDate;
- @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
- private Date uploadTime;
- @Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
- private String previewUrl;
- }
OFFICE_INDEX为设置好的全局常量,内容为:gt_office_doc (也就是index)
其中,初始化数据时候,是从数据库中查询LIST而后插入ES(批量操作)
@Async为异步请求,考虑当数据库中的数据较多,反应时间较长,加载批量操作数据的方法中
其中,全字段检索使用了multiMatchQuery,将需要匹配的字段写入,则可按照查询。
- import static com.icss.audit.gt.constant.CommonConst.OFFICE_INDEX;
- /**
- * @author hmf
- * @create 2022-08-29
- */
- @Slf4j
- @Service
- public class EsIndexService {
-
- @Resource
- ElasticsearchRestTemplate elasticsearchRestTemplate;
-
- @Autowired
- private RestHighLevelClient restHighLevelClient;
-
- @Resource
- OfficeDocumentDao officeDocumentDao;
-
- /**
- * 创建索引
- */
- public void createIndex() throws Exception {
- if (elasticsearchRestTemplate.indexOps(IndexCoordinates.of(OFFICE_INDEX)).exists()){
- deleteIndex();
- }
- // 创建索引配置信息,配置
- Settings settings = Settings.builder()
- .put("index.number_of_shards", 1)
- .put("index.number_of_replicas", 0)
- .build();
- // 新建创建索引请求对象,然后设置索引类型(ES 7.0 将不存在索引类型)和 mapping 与 index 配置
- CreateIndexRequest request = new CreateIndexRequest(OFFICE_INDEX, settings);
- // RestHighLevelClient 执行创建索引
- CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
- // 判断是否创建成功
- boolean isCreated = createIndexResponse.isAcknowledged();
- if (isCreated){
- //初始化数据
- initEsData();
- }
- }
-
- /**
- * 删除索引
- */
- public void deleteIndex()throws Exception {
- // 新建删除索引请求对象
- DeleteIndexRequest request = new DeleteIndexRequest(OFFICE_INDEX);
- // 执行删除索引
- AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
- // 判断是否删除成功
- log.info("索引是否删除成功:" + acknowledgedResponse.isAcknowledged());
- }
-
- /**
- * 初始化索引数据
- */
- @Async
- public void initEsData() throws Exception{
-
- List<OfficeDocVO> resultlist = officeDocumentDao.initIndexData();
- //增加预览参数
- for(OfficeDocVO temp : resultlist){
- if (temp.getDocFileName().endsWith(".pdf")){
- temp.setPreviewUrl("/officeDocument/PreviewOfficeDoc?id=");
- }
- }
- // 创建索引请求对象
- BulkRequest bulkRequest = new BulkRequest();
- // 准备批量插入的数据
- resultlist.forEach(user -> {
- // 设置请求对象
- IndexRequest request = new IndexRequest(OFFICE_INDEX);
- // 文档id
- request.id(user.getOfficeDocId());
- // 将json格式字符串放在请求中
- // 下面这种写法也可以写成:request.source(XContentType.JSON, "name", "张三", "age", "男", "age", 22);,其中"name"、"age"、 "age"是User对象中的字段名,而这些字段名称后面的值就是对应的值
- System.out.println("插入的数据为:"+user.toString());
- request.source(JSONObject.toJSONString(user), XContentType.JSON);
- // 将request添加到批量处理请求中
- bulkRequest.add(request);
- });
- // 3、发送请求到ES
- BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
- // 4、处理响应结果
- log.info("批量插入是否失败:" + response.hasFailures());
- }
-
- /**
- * 获取所有文档信息
- */
- public SearchResponse getDocument(PageData page) throws IOException {
- // 获取请求对象
- SearchRequest getRequest = new SearchRequest(OFFICE_INDEX, "", "");
- // 指定检索条件
- SearchSourceBuilder builder = new SearchSourceBuilder();
-
- Map<String, Object> condition = page.getCondition();
- String AuthorityYear = "";
- String Authority = "";
- String ownerUnit = "";
-
- int currentPage = (int) page.getCurrent();
- int pageSize = 10;
- int from = (currentPage - 1) * pageSize;
- builder.from(from);
- builder.size(pageSize);
-
- // 若无参则用来查询索引中全部的数据
- builder.query(QueryBuilders.matchAllQuery());
- getRequest.source(builder);
-
- if (condition != null) {
- if (condition.get("AuthorityYear") != "") {
- AuthorityYear = (String) condition.get("AuthorityYear");
- builder.query(QueryBuilders.termQuery("issuingAuthorityYear.keyword", AuthorityYear));
- getRequest.source(builder);
- }
- if (condition.get("Authority") != "") {
- Authority = condition.get("Authority").toString();
- builder.query(QueryBuilders.termQuery("dispatchnoId.keyword", Authority));
- getRequest.source(builder);
- }
- /*全文检索*/
- if (condition.get("ownerUnit") != ""){
- ownerUnit = condition.get("ownerUnit").toString();
- //多个字段条件匹配查询(multiMatchQuery)
- builder.query(QueryBuilders.multiMatchQuery(ownerUnit,"docTitle","issuingAuthority","issuingAuthorityYear","postingSequenceNumber","orgName","drafterName","uploaderName"));
- getRequest.source(builder);
- }
- }
- // 3、发送请求到ES
- return restHighLevelClient.search(getRequest, RequestOptions.DEFAULT);
-
- // // 4、处理响应结果
- // for (SearchHit hit : response.getHits().getHits()) {
- // OfficeDocVO officeInfo = JSON.parseObject(hit.getSourceAsString(), OfficeDocVO.class);
- // log.info("所有信息:{}", officeInfo);
- // }
-
- }
-
- /**
- * 新增索引数据
- */
- public void addEsDoc(OfficeDocVO officeDocVO)throws IOException{
- // 定义请求对象
- IndexRequest request = new IndexRequest(OFFICE_INDEX);
- // 设置文档id
- request.id(officeDocVO.getOfficeDocId());
- // 将json格式字符串放在请求中
- request.source(JSONObject.toJSONString(officeDocVO), XContentType.JSON);
- // 3、发送请求到ES
- IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
-
- }
-
- /**
- * 更新索引数据
- */
- public void updateEsDoc(OfficeDocVO officeDocVO)throws IOException{
- UpdateRequest request = new UpdateRequest();
- request.index(OFFICE_INDEX).id(officeDocVO.getOfficeDocId());
- // 拓展:局部更新也可以这样写:request.doc(XContentType.JSON, "name", "李四", "age", 25);,其中"name"和"age"是User对象中的字段名称,而"小美"和20是对应的字段值
- request.doc(JSONObject.toJSONString(officeDocVO), XContentType.JSON);
- // 3、发送请求到ES
- UpdateResponse response = restHighLevelClient.update(request, RequestOptions.DEFAULT);
- }
-
- /**
- * 删除索引数据
- * @param OfficeDocId
- * @throws Exception
- */
- public void deleteEsDoc(String OfficeDocId)throws Exception{
- // 2、定义请求对象
- DeleteRequest request = new DeleteRequest(OFFICE_INDEX);
- request.id(OfficeDocId);
- // 3、发送请求到ES
- DeleteResponse response = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
- }
- }
- /**
- * @author hmf
- * @create 2022-08-26 10:44
- */
- @Api(tags = "ES全文检索")
- @RestController
- @CrossOrigin
- @RequestMapping("/EsSearch")
- public class EsSearchContoller {
-
- @Resource
- RestHighLevelClient client;
-
-
- @Resource
- EsIndexService esIndexService;
-
-
- @ApiOperation("初始化ES数据以及index")
- @RequestMapping("/initIndex")
- public void createIndex()throws Exception{
- esIndexService.createIndex();
- }
-
- @ApiOperation("ES数据查询以及全文检索")
- @RequestMapping("/getEsData")
- public SearchResponse getEsData(@RequestBody PageData page)throws IOException{
- return esIndexService.getDocument(page);
- }
-
-
-
- }
需要注意从ES查询出来的返回值存储在res.hits.hits中
由于传输中,将数据库里的数据时间类型转入ES后会转成时间戳,返回前端后展示数据会变成时间戳。
在后端加注解也是方法之一,
但这里是用前端进行转换。
- // 表格初始化
- Initialization(data){
- let condition = {
- AuthorityYear:data.parentid,
- Authority:data.dispatchnoId,
- ownerUnit:this.formInline.ownerUnit,
- };
- let size = this.page.size;
- let current=this.page.currentPage;
- let Params = {condition,size,current}
- this.request('/EsSearch/getEsData',Params,'post').then((res) =>{
- if (res.hits.hits.length > 0){
- res.hits.hits.forEach(element => {
- element.sourceAsMap.draftDate = this.Time(element.sourceAsMap.draftDate);
- element.sourceAsMap.uploadTime = this.Time(element.sourceAsMap.uploadTime);
- });
- this.tableData = res.hits.hits;
- }else{
- //表格重置为空
- this.tableData=[];
- }
- //重置显示总数
- this.page.total=res.hits.totalHits.value;
- })
- },
- Time(time) { //处理时间
- // return moment(parseInt(e)).format('YYYY-MM-DD');
- //将13位时间戳转换成时间格式 输出为2018-10-09
- let date = new Date(time);
- let year = date.getFullYear();
- let month = date.getMonth() + 1;
- let day = date.getDate();
- month = month < 10 ? "0" + month : month;
- day = day < 10 ? "0" + day : day;
- var myDate = ''
- myDate = year + '-' + month + '-' + day;
- return myDate
- },
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。