mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/per-boe/java-servers.git
synced 2025-12-08 10:26:48 +08:00
案例专家:增加手动刷新索引功能
This commit is contained in:
@@ -1,22 +1,12 @@
|
||||
package com.xboe.config;
|
||||
|
||||
import com.xboe.module.boecase.service.IElasticSearchIndexService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.elasticsearch.client.indices.CreateIndexRequest;
|
||||
import org.elasticsearch.client.indices.CreateIndexResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexRequest;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* ElasticSearch索引初始化器
|
||||
* 在Spring Boot启动完成并监听到配置文件加载完毕后,检查并创建所需的ES索引
|
||||
@@ -27,8 +17,8 @@ import java.io.IOException;
|
||||
@Component
|
||||
public class ElasticSearchIndexInitializer {
|
||||
|
||||
@Autowired(required = false)
|
||||
private RestHighLevelClient elasticsearchClient;
|
||||
@Autowired
|
||||
private IElasticSearchIndexService elasticSearchIndexService;
|
||||
|
||||
/**
|
||||
* 监听Spring Boot应用启动完成事件
|
||||
@@ -36,158 +26,12 @@ public class ElasticSearchIndexInitializer {
|
||||
*/
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void initializeElasticSearchIndices() {
|
||||
if (elasticsearchClient == null) {
|
||||
log.warn("ElasticSearch客户端未配置,跳过索引初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("开始检查和初始化ElasticSearch索引...");
|
||||
|
||||
try {
|
||||
// 检查并创建ai_chat_messages索引
|
||||
checkAndCreateIndex("ai_chat_messages");
|
||||
|
||||
log.info("ElasticSearch索引初始化完成");
|
||||
} catch (Exception e) {
|
||||
log.error("ElasticSearch索引初始化失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查索引是否存在,如果不存在则创建
|
||||
*
|
||||
* @param indexName 索引名称
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
private void checkAndCreateIndex(String indexName) throws IOException {
|
||||
// 检查索引是否存在
|
||||
GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
|
||||
boolean exists = elasticsearchClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
|
||||
|
||||
if (exists) {
|
||||
log.info("ElasticSearch索引 [{}] 已存在", indexName);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("ElasticSearch索引 [{}] 不存在,开始创建...", indexName);
|
||||
|
||||
// 创建索引
|
||||
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
|
||||
|
||||
// 设置索引配置
|
||||
createIndexRequest.settings(Settings.builder()
|
||||
.put("index.number_of_shards", 1)
|
||||
.put("index.number_of_replicas", 0)
|
||||
.put("index.analysis.analyzer.ik_max_word.tokenizer", "ik_max_word")
|
||||
.put("index.analysis.analyzer.ik_smart.tokenizer", "ik_smart")
|
||||
);
|
||||
|
||||
// 设置字段映射
|
||||
String mapping = getAiChatMessagesMapping();
|
||||
createIndexRequest.mapping(mapping, XContentType.JSON);
|
||||
|
||||
// 执行创建索引请求
|
||||
CreateIndexResponse createIndexResponse = elasticsearchClient.indices()
|
||||
.create(createIndexRequest, RequestOptions.DEFAULT);
|
||||
|
||||
if (createIndexResponse.isAcknowledged()) {
|
||||
log.info("ElasticSearch索引 [{}] 创建成功", indexName);
|
||||
String indexName = "ai_chat_messages";
|
||||
if (elasticSearchIndexService.checkIndexExists(indexName)) {
|
||||
log.info("ElasticSearch索引 ai_chat_messages 已存在");
|
||||
} else {
|
||||
log.warn("ElasticSearch索引 [{}] 创建可能失败,响应未确认", indexName);
|
||||
log.info("ElasticSearch索引 ai_chat_messages 不存在,开始创建...");
|
||||
elasticSearchIndexService.createIndex(indexName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ai_chat_messages索引的字段映射配置
|
||||
* 根据项目中的会话消息数据结构规范定义映射
|
||||
*
|
||||
* @return JSON格式的映射配置
|
||||
*/
|
||||
private String getAiChatMessagesMapping() {
|
||||
return "{\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"conversationId\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"messageId\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"messageType\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"query\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\",\n" +
|
||||
" \"fields\": {\n" +
|
||||
" \"keyword\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"ignore_above\": 256\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"answer\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\"\n" +
|
||||
" },\n" +
|
||||
" \"caseRefer\": {\n" +
|
||||
" \"type\": \"nested\",\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"caseId\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"title\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\"\n" +
|
||||
" },\n" +
|
||||
" \"authorName\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"keywords\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\"\n" +
|
||||
" },\n" +
|
||||
" \"content\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"suggestions\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\"\n" +
|
||||
" },\n" +
|
||||
" \"userId\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"userName\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"timestamp\": {\n" +
|
||||
" \"type\": \"date\",\n" +
|
||||
" \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSS'Z'||epoch_millis\"\n" +
|
||||
" },\n" +
|
||||
" \"createTime\": {\n" +
|
||||
" \"type\": \"date\",\n" +
|
||||
" \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSS'Z'||epoch_millis\"\n" +
|
||||
" },\n" +
|
||||
" \"updateTime\": {\n" +
|
||||
" \"type\": \"date\",\n" +
|
||||
" \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSS'Z'||epoch_millis\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.xboe.core.JsonResponse;
|
||||
import com.xboe.module.boecase.dto.CaseAiChatDto;
|
||||
import com.xboe.module.boecase.service.ICaseAiChatService;
|
||||
import com.xboe.module.boecase.service.ICaseAiPermissionService;
|
||||
import com.xboe.module.boecase.service.IElasticSearchIndexService;
|
||||
import com.xboe.module.boecase.vo.CaseAiMessageVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -36,6 +37,9 @@ public class CaseAiChatApi extends ApiBaseController {
|
||||
@Autowired
|
||||
private ICaseAiPermissionService caseAiPermissionService;
|
||||
|
||||
@Autowired
|
||||
private IElasticSearchIndexService elasticSearchIndexService;
|
||||
|
||||
/**
|
||||
* 聊天
|
||||
* @param caseAiChatDto
|
||||
@@ -83,4 +87,23 @@ public class CaseAiChatApi extends ApiBaseController {
|
||||
return error("判断失败", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动刷新索引
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/index/refresh")
|
||||
public JsonResponse<String> deleteAndCreateEsIndex() {
|
||||
String indexName = "ai_chat_messages";
|
||||
if (elasticSearchIndexService.checkIndexExists(indexName)) {
|
||||
boolean deleteResult = elasticSearchIndexService.deleteIndex(indexName);
|
||||
if (deleteResult) {
|
||||
elasticSearchIndexService.createIndex(indexName);
|
||||
return success("刷新成功");
|
||||
}
|
||||
} else {
|
||||
elasticSearchIndexService.createIndex(indexName);
|
||||
}
|
||||
return error("刷新失败");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.xboe.module.boecase.service;
|
||||
|
||||
/**
|
||||
* es索引
|
||||
*/
|
||||
public interface IElasticSearchIndexService {
|
||||
|
||||
/**
|
||||
* 查看索引是否存在
|
||||
* @param indexName
|
||||
* @return
|
||||
*/
|
||||
boolean checkIndexExists(String indexName);
|
||||
|
||||
/**
|
||||
* 创建索引
|
||||
* @param indexName
|
||||
*/
|
||||
boolean createIndex(String indexName);
|
||||
|
||||
/**
|
||||
* 删除索引
|
||||
* @param indexName
|
||||
* @return
|
||||
*/
|
||||
boolean deleteIndex(String indexName);
|
||||
}
|
||||
@@ -217,8 +217,8 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
|
||||
// 8. 执行HTTP请求
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.connectTimeout(60, TimeUnit.SECONDS)
|
||||
.writeTimeout(60, TimeUnit.SECONDS)
|
||||
.readTimeout(60, TimeUnit.SECONDS)
|
||||
.writeTimeout(600, TimeUnit.SECONDS)
|
||||
.readTimeout(600, TimeUnit.SECONDS)
|
||||
.build();
|
||||
EventSource.Factory factory = EventSources.createFactory(client);
|
||||
factory.newEventSource(request, listener);
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
package com.xboe.module.boecase.service.impl;
|
||||
|
||||
import com.xboe.module.boecase.service.IElasticSearchIndexService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.elasticsearch.client.indices.CreateIndexRequest;
|
||||
import org.elasticsearch.client.indices.CreateIndexResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexRequest;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class ElasticSearchIndexServiceImpl implements IElasticSearchIndexService {
|
||||
|
||||
@Autowired(required = false)
|
||||
private RestHighLevelClient elasticsearchClient;
|
||||
|
||||
@Override
|
||||
public boolean checkIndexExists(String indexName) {
|
||||
if (elasticsearchClient == null) {
|
||||
log.warn("ElasticSearch客户端未配置");
|
||||
return false;
|
||||
}
|
||||
// 检查索引是否存在
|
||||
GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
|
||||
try {
|
||||
return elasticsearchClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
|
||||
} catch (IOException e) {
|
||||
log.error("查询ElasticSearch索引时发生异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createIndex(String indexName) {
|
||||
if (elasticsearchClient == null) {
|
||||
log.warn("ElasticSearch客户端未配置");
|
||||
return false;
|
||||
}
|
||||
// 创建索引
|
||||
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
|
||||
|
||||
// 设置索引配置
|
||||
createIndexRequest.settings(Settings.builder()
|
||||
.put("index.number_of_shards", 1)
|
||||
.put("index.number_of_replicas", 0)
|
||||
.put("index.analysis.analyzer.ik_max_word.tokenizer", "ik_max_word")
|
||||
.put("index.analysis.analyzer.ik_smart.tokenizer", "ik_smart")
|
||||
);
|
||||
|
||||
// 设置字段映射
|
||||
String mapping = getAiChatMessagesMapping();
|
||||
createIndexRequest.mapping(mapping, XContentType.JSON);
|
||||
|
||||
// 执行创建索引请求
|
||||
CreateIndexResponse createIndexResponse = null;
|
||||
try {
|
||||
createIndexResponse = elasticsearchClient.indices()
|
||||
.create(createIndexRequest, RequestOptions.DEFAULT);
|
||||
} catch (IOException e) {
|
||||
log.error("创建ElasticSearch索引时发生异常", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (createIndexResponse.isAcknowledged()) {
|
||||
log.info("ElasticSearch索引 [{}] 创建成功", indexName);
|
||||
return true;
|
||||
} else {
|
||||
log.warn("ElasticSearch索引 [{}] 创建可能失败,响应未确认", indexName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteIndex(String indexName) {
|
||||
if (elasticsearchClient == null) {
|
||||
log.warn("ElasticSearch客户端未配置");
|
||||
return false;
|
||||
}
|
||||
// 执行删除索引请求
|
||||
DeleteIndexRequest deleteRequest = new DeleteIndexRequest(indexName);
|
||||
try {
|
||||
AcknowledgedResponse deleteResponse = elasticsearchClient.indices().delete(deleteRequest, RequestOptions.DEFAULT);
|
||||
if (deleteResponse.isAcknowledged()) {
|
||||
log.info("成功删除Elasticsearch索引: {}", indexName);
|
||||
return true;
|
||||
} else {
|
||||
log.warn("删除索引 [{}] 未被确认(可能部分节点未响应)", indexName);
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("删除ElasticSearch索引时发生异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ai_chat_messages索引的字段映射配置
|
||||
* 根据项目中的会话消息数据结构规范定义映射
|
||||
*
|
||||
* @return JSON格式的映射配置
|
||||
*/
|
||||
private String getAiChatMessagesMapping() {
|
||||
return "{\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"conversationId\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"messageId\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"messageType\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"query\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\",\n" +
|
||||
" \"fields\": {\n" +
|
||||
" \"keyword\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"ignore_above\": 256\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"answer\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\"\n" +
|
||||
" },\n" +
|
||||
" \"caseRefer\": {\n" +
|
||||
" \"type\": \"nested\",\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"caseId\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"title\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\"\n" +
|
||||
" },\n" +
|
||||
" \"authorName\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"keywords\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\"\n" +
|
||||
" },\n" +
|
||||
" \"content\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"suggestions\": {\n" +
|
||||
" \"type\": \"text\",\n" +
|
||||
" \"analyzer\": \"ik_max_word\",\n" +
|
||||
" \"search_analyzer\": \"ik_smart\"\n" +
|
||||
" },\n" +
|
||||
" \"userId\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"userName\": {\n" +
|
||||
" \"type\": \"keyword\",\n" +
|
||||
" \"index\": true\n" +
|
||||
" },\n" +
|
||||
" \"timestamp\": {\n" +
|
||||
" \"type\": \"date\",\n" +
|
||||
" \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSS'Z'||epoch_millis\"\n" +
|
||||
" },\n" +
|
||||
" \"createTime\": {\n" +
|
||||
" \"type\": \"date\",\n" +
|
||||
" \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSS'Z'||epoch_millis\"\n" +
|
||||
" },\n" +
|
||||
" \"updateTime\": {\n" +
|
||||
" \"type\": \"date\",\n" +
|
||||
" \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSS'Z'||epoch_millis\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user