elasticsearch7.14.0最新版的操作集合,以及對elasticsearch和mybatis-plus整合,
前言
- 就算不用這個框架,用這個來魔改一下也挺不錯哦🤪
- 該框架是在springboot中對elasticsearch的方法進行包裝,同時整合mybatis-plus和elasticsearch(利用mybatis-plus的攔截器來完成自動增刪改)
- 不用在給每個類配置一個獨一無二的增刪改操作了,且能夠自動的實作elasticsearch的增刪改操作,以及自動創建index,還有es的搜索功能、支持高亮顯示、must匹配和should匹配、list串列分頁獲取資料,
- 版本使用:
- elasticsearch 7.14.0 最新版本
- springboot 2.4.1
- 自定義的yml配置
smart-es:
client-config:
hostname: # 服務器ip
port: 9200
scheme: http
username: # es給你生成的用戶名
password: # es給你生成的密碼
service-config:
pre-tags: <span class="highlight">
post-tags: </span>
pkg: cn.omisheep.spook.entity # 物體類包名
1. 自動創建索引
如下,有三個注解,分別是@Index,@IndexId,@IndexField,
@Data
@Index
@TableName("article")
@Accessors(chain = true)
public class Article {
@TableId(value = "id", type = IdType.AUTO)
@IndexId
private Integer id;
@IndexField(isSearch = false)
private String userAvatar;
@IndexField
private String type;
@IndexField
private String tags;
@IndexField
private String title;
@IndexField(searchAnalyzer = "ik_smart")
private String content;
@IndexField(isSearch = false)
private String firstPicture;
@IndexField
private String description;
@IndexField
private Integer views; // 瀏覽量
@IndexField
@TableField(value = "`like`")
private Integer like; // 瀏覽量
@IndexField
private Date createTime;
}
@Index
該注解用于物體類上面,被注解標記的物體類在springboot運行時會自動判斷你的服務器有沒有對應的索引,如果沒有會創建,有的話會update,稍后說,
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Index {
String value() default ""; // 索引名
}
-
@IndexId該注解用于屬性上,被該注解標記的物體類在創建index時或者資料自動增刪改時會將其當作es的id,什么型別無所謂,型別會自動轉成string,
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IndexId {
}
-
@IndxField該注解用于屬性上,被該注解標記的物體類顧名思義就是index里面的屬性,可以自定義搜索方式,分詞方式,指定型別,指定名稱,基礎型別可以不寫,其他的,比如String型別可以有text或者keyword,默認text,
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IndexField {
String value() default ""; // 欄位名,默認為屬性名
String type() default ""; // 欄位型別,如text等,可以不設定,會默認根據java型別來轉換
String analyzer() default "ik_max_word"; // 在型別為text時生效
String searchAnalyzer() default "ik_max_word"; // 在型別為text時生效
/**
* 默認為true參與搜索,
* false時不參與搜索,只作為內容傳遞,但在指定should和must搜索下仍然能被搜索
*/
boolean isSearch() default true;
}
2. 增刪改統一方法
? 如下,比如在ElasticSearchService類中,使用
@Autowired
private ArticleMapper articleMapper;
@Autowired
private ElasticSearchService elasticSearchService;
public int releaseArticle(Article article, User user) {
article.setUserId(user.getId()).setUserAvatar(user.getAvatar());
int insert = articleMapper.insert(article);
elasticSearchService.insert(article);
// elasticSearchService.update(article);
return insert;
}
眾所周知,因為mybatis的特性,當你插入一個資料時,如果你想這個id由資料庫生成,然后在你插入返還id給你,你得重寫從物件里面取出來,比如:
articleMapper.insert(article);
int id = article.getId();
看上面,只需要一行代碼就能實作插入,使用邏輯和mybatis-plus基本一致
當然,你可以不寫,借助mybatis-plus給你的攔截器,你可以在所有mapper呼叫insert方法之后去攔截她,然后在攔截器中寫上這個方法,因為所有的類使用都是一個模樣elasticSearchService.insert(object);,
- 攔截器如下
@Slf4j
@Intercepts(@Signature(type = Executor.class, method = "update", args = {MappedStatement.class,
Object.class}))
public class ESAop implements Interceptor {
@Autowired
private ElasticSearchService elasticSearchService;
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object proceed = invocation.proceed(); // 這個就是mapper的方法執行
fun(mappedStatement.getId(), invocation.getArgs()[1]);
return proceed;
}
public Object plugin(Object o) {
return Plugin.wrap(o, this);
}
public void setProperties(Properties properties) {
}
@SneakyThrows
private void fun(String method, Object parameter) {
int i = method.lastIndexOf(".");
String className = method.substring(0, i);
String methodName = method.substring(i + 1);
ParameterizedType parameterizedType =
(ParameterizedType) Class.forName(className)
.getGenericInterfaces()[0];
Class<?> clz = (Class<?>) parameterizedType.getActualTypeArguments()[0];
if (!elasticSearchService.isIndex(clz)) {
return;
}
switch (methodName) { // 在這里添加自定義方法,如果不熟悉,可以打個斷點
case "insert": {
if (clz == parameter.getClass()) {
elasticSearchService.insert(parameter);
}
break;
}
case "updateById":
Object o = ((MapperMethod.ParamMap) parameter).get("param1");
if (clz == o.getClass()) {
elasticSearchService.insert(parameter);
}
elasticSearchService.insert(o);
break;
case "deleteById": {
elasticSearchService.delete(clz.getName(), parameter + "");
break;
}
}
}
}
自定義的mapper方法需要攔截,你需要動動你的小手自己加上去,,,
- 再來看看insert這個方法,其他方法大同小異
/**
* 請在save之后呼叫此方法,否則獲得不到id,這樣在插入到es服務器中,id是隨機的,
*/
@SneakyThrows
public <E> int insert(E o) {
log.info(" elastic service insert {}", o);
Meta meta = new Meta(o);
IndexRequest request = new IndexRequest(meta.getIndexName())
.id(meta.getIndexId())
.timeout("3s")
.source(meta.getSource());
return client.index(request, RequestOptions.DEFAULT).status().getStatus();
}
很明顯,引數是不是固定的,所以可以實作插入任意的物體類,這個service有點長,在最后貼出來,
Meta meta = new Meta(o); // 這一行代碼就是根據之前的一些注解來包裝成一個物件,
還有一些其他的如update delete啥的放在最后了,或者去gitee上下載下來,https://gitee.com/iozxc/smart-es
3. 搜索查詢
搜索就不看service的代碼了,直接看controller如何呼叫的
@RestController
@RequestMapping
@Slf4j
public class SearchController {
@Autowired
private ElasticSearchService elasticSearchService;
@GetMapping(value = {"/search", "/s"})
public Result search(@RequestParam(value = "kw", required = false) String keyword,
@RequestParam(required = false) Integer pageNo,
@RequestParam(required = false) Integer pageSize,
@RequestParam(required = false) String type,
@RequestParam(required = false) String index,
@RequestParam(required = false) String must,
@RequestParam(required = false) String should,
@RequestParam(value = "highlight", required = false, defaultValue = "true") Boolean isHighlight) {
if (keyword == null) {
return new Result(ResultCode.SUCCESS);
}
HashMap<String, List<Object>> search = elasticSearchService.search(keyword, pageNo, pageSize, type, index, must, should, isHighlight);
return new Result(ResultCode.SUCCESS, search);
}
@GetMapping(value = {"/list", "/l"})
public Result list(@RequestParam(value = "i", required = false) String index,
@RequestParam(required = false) Integer pageNo,
@RequestParam(required = false) Integer pageSize,
@RequestParam(required = false) String sortName,
@RequestParam(required = false) String order) {
if (index == null) {
return new Result(ResultCode.SUCCESS);
}
HashMap<String, List<Object>> list = elasticSearchService.list(pageNo, pageSize, index, sortName, order);
return new Result(ResultCode.SUCCESS, list);
}
}
- search方法,根據關鍵字,在指定的index里面搜索,支持分頁,可以指定搜索的欄位,以及是must還是should,同時是否要高亮顯示,
public HashMap<String, List<Object>> search(String keyword,
Integer pageNo,
Integer pageSize,
String type,
String index,
String must,
String should,
Boolean isHighlight){...}
index這個欄位可以寫成如 user,blog,comment 這種格式用逗號隔開,must,should同理,
type為只有在must和should都為null時才生效,默認把指定index的指定型別的所有內容全部查詢出來,
- list 方法,得到一個排序的集合,支持分頁,
public HashMap<String, List<Object>> list(Integer pageNo,
Integer pageSize,
String index,
String sortName,
String order)
index指定的indx名,用法和search一樣,可以多個,
sortName排序的欄位名,可以為空,使用默認排序
order排序方式 ASC 或者 DESC
以上兩個方法的回傳值格式如圖
{
"article": [
{
"createTime": "xx-xx-xx xx:xx:xx",
"like": 123123,
"userAvatar": "",
"description": "nihaoa ",
"id": "21",
"content": "zxc",
"views": 999,
"tags": "<span class=\"highlight\">love</span>"
},
{
"createTime": "xx-xx-xx xx:xx:xx",
"like": 123123,
"userAvatar": "",
"description": "nihaoa ",
"id": "29",
"content": "zxc",
"views": 999,
"tags": "<span class=\"highlight\">love</span>"
},
],
"user": [{
...
}],
"xxx": [{
...
}]
}
- 最后貼上其他所有的代碼,還有一些工具類,就不貼出來了,
ESConfig
@Configuration
@ConfigurationProperties(
prefix = "smart-es"
)
@Data
public class ESConfig {
private ClientConfig clientConfig;
private ServiceConfig serviceConfig;
@Data
public static class ClientConfig {
private String hostname;
private Integer port;
private String scheme;
private String username;
private String password;
}
@Data
public static class ServiceConfig {
private String pkg = "cn.omisheep.spook.entity"; // 物體類掃描的包名
private String preTags = "<span class=\"highlight\">"; // 高亮顯示的前綴
private String postTags = "</span>"; // 高亮顯示的后綴
private int defaultPageSize = 10;
}
}
ElasticSearchClient
@Configuration
@Data
public class ElasticSearchClient {
private final ESConfig.ClientConfig config;
public ElasticSearchClient(ESConfig esConfig) {
this.config = esConfig.getClientConfig();
}
@Bean
public RestHighLevelClient restHighLevelClient() {
HttpHost httpHost = new HttpHost(config.getHostname(), config.getPort(), config.getScheme());
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(config.getUsername(), config.getPassword()));
RestClientBuilder builder = RestClient.builder(httpHost)
.setRequestConfigCallback(requestConfigBuilder -> {
requestConfigBuilder.setConnectTimeout(-1);
requestConfigBuilder.setSocketTimeout(-1);
requestConfigBuilder.setConnectionRequestTimeout(-1);
return requestConfigBuilder;
}).setHttpClientConfigCallback(httpClientBuilder -> {
httpClientBuilder.disableAuthCaching();
return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
});
return new RestHighLevelClient(builder);
}
}
ElasticSearchService
@Service
@Slf4j
public class ElasticSearchService {
private final ESConfig.ServiceConfig config;
/**
* 系統屬性
*/
private final RestHighLevelClient client;
/**
* 時間型別
*/
private final String dateFormat = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"; // 搜索時的空欄位
private SimpleDateFormat simpleDateFormat;
/**
* 型別轉換
*/
private static final String[] javaTypes = {"String", "Integer", "Double", "Float", "Boolean", "Date", "*"};
private static final String[] esTypes = {"text", "integer", "double", "float", "boolean", "date", "unknown"};
/**
* className ==> indexName
*/
private static final Map<String, String> indexMap = new HashMap<>();
/**
* indexName ==> indexId
*/
private static final Map<String, Field> indexIdMap = new HashMap<>();
/**
* indexName ==> filedMap
*/
private static final Map<String, Map<String, Field>> indexFiledMap = new HashMap<>();
/**
* 所有的index
*/
private static String[] allIndex;
/**
* indexName => {text=>[]}
*/
private static final Map<String, Map<String, List<String>>> typeFieldMix = new HashMap<>();
public ElasticSearchService(@Qualifier("restHighLevelClient") RestHighLevelClient client,
ESConfig esConfig) {
this.client = client;
this.config = esConfig.getServiceConfig();
initIndex();
log.info("init ElasticSearchService successfully");
}
private String parseType(Field field) {
IndexField indexField = field.getAnnotation(IndexField.class);
if (indexField.type().equals("")) {
for (int i = 0; i < javaTypes.length; i++) {
if (javaTypes[i].equals(field.getType().getSimpleName())) {
return esTypes[i];
}
}
} else {
return indexField.type();
}
return "unknown";
}
private HashMap<String, Object> parseClassToMapping(Class<?> clz) throws Exception {
Map<String, Field> fieldMap = indexFiledMap.get(indexMap.get(clz.getName()));
if (fieldMap == null) return null;
HashMap<String, Object> createIndexMap = new HashMap<>();
HashMap<String, Object> properties = new HashMap<>();
for (Map.Entry<String, Field> entry : fieldMap.entrySet()) {
HashMap<String, String> info = new HashMap<>();
Field field = entry.getValue();
IndexField indexField = field.getAnnotation(IndexField.class);
String type = parseType(field);
info.put("type", type);
if (type.equals("unknown")) {
throw new Exception("elasticsearch型別例外");
} else if (type.equals("text")) {
info.put("analyzer", indexField.analyzer());
info.put("search_analyzer", indexField.searchAnalyzer());
} else if (type.equals("date")) {
info.put("format", dateFormat);
}
properties.put(entry.getKey(), info);
}
createIndexMap.put("properties", properties);
return createIndexMap;
}
public boolean isIndex(Class<?> clz) {
Index index = clz.getDeclaredAnnotation(Index.class);
return index != null;
}
@SneakyThrows
public boolean createIndex(Class<?> clz) {
if (!isIndex(clz)) {
log.error("create index error , class: {} . require a annotation @Index", clz.getName());
return false;
}
HashMap<String, Object> createIndexMap = parseClassToMapping(clz);
String indexName = indexMap.get(clz.getName());
log.debug("createIndexMap . index: {} class: {} => {}", indexName, clz.getName(), createIndexMap);
CreateIndexRequest request = new CreateIndexRequest(indexName)
.mapping(createIndexMap);
boolean acknowledged = client.indices()
.create(request, RequestOptions.DEFAULT).isAcknowledged();
if (acknowledged) {
log.info("create index {} is successfully", indexName);
} else {
log.error("create index {} is fail", indexName);
}
return acknowledged;
}
public boolean isExistIndex(Class<?> clz) throws IOException {
GetIndexRequest request = new GetIndexRequest(indexMap.get(clz.getName()));
return client.indices().exists(request, RequestOptions.DEFAULT);
}
public boolean isAllExistIndex() throws IOException {
GetIndexRequest request = new GetIndexRequest(
indexMap.keySet().toArray(ConstantPool.EMPTY_STRINGS)
);
return client.indices().exists(request, RequestOptions.DEFAULT);
}
/**
* 只能增刪mapping,不能修改
*
* @param clz 對應的index物體類
*/
public boolean updateIndex(Class<?> clz) throws Exception {
if (!isIndex(clz)) {
throw new Exception("不是index");
}
PutMappingRequest request = new PutMappingRequest(indexMap.get(clz.getName()));
HashMap<String, Object> mapping = parseClassToMapping(clz);
request.source(mapping);
log.info("{} try update index => {}", indexMap.get(clz.getName()), mapping);
try {
return client.indices().putMapping(request, RequestOptions.DEFAULT).isAcknowledged();
} catch (IOException e) {
log.error("不能修改型別,請洗掉索引重新添加資料");
throw e;
}
}
/**
* 請在save之后呼叫此方法
*/
@SneakyThrows
public <E> int insert(E o) {
log.info(" elastic service insert {}", o);
Meta meta = new Meta(o);
IndexRequest request = new IndexRequest(meta.getIndexName())
.id(meta.getIndexId())
.timeout("3s")
.source(meta.getSource());
return client.index(request, RequestOptions.DEFAULT).status().getStatus();
}
@SneakyThrows
public <E> boolean insert(List<E> list) {
log.info(" elastic service insert list: {}", list);
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
for (E o : list) {
Meta meta = new Meta(o);
bulkRequest.add(
new IndexRequest(meta.getIndexName())
.id(meta.getIndexId())
.source(meta.getSource())
);
}
BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
log.info("insert a list => {}", list);
return bulk.hasFailures();
}
@SneakyThrows
public <E> int update(E o) {
log.info(" elastic service update ");
Meta meta = new Meta(o);
UpdateRequest request = new UpdateRequest(
meta.getIndexName(), meta.getIndexId())
.doc(meta.getSource());
return client.update(request, RequestOptions.DEFAULT).status().getStatus();
}
@SneakyThrows
public <E> boolean update(List<E> list) {
log.info(" elastic service update list {}", list);
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
for (E o : list) {
Meta meta = new Meta(o);
bulkRequest.add(
new UpdateRequest(
meta.getIndexName(), meta.getIndexId())
.doc(meta.getSource())
);
}
BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
return bulk.hasFailures();
}
@SneakyThrows
public int delete(String clzName, String id) {
log.info(" elastic service delete ");
DeleteRequest request = new DeleteRequest(
indexMap.get(clzName), id)
.timeout("2s");
return client.delete(request, RequestOptions.DEFAULT).status().getStatus();
}
@SneakyThrows
public boolean delete(String clzName, List<String> list) {
log.info(" elastic service delete ");
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
String indexName = indexMap.get(clzName);
for (String id : list) {
bulkRequest.add(
new DeleteRequest(indexName, id).timeout("2s")
);
}
BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
return bulk.hasFailures();
}
private String[] sp(String str) {
if (str == null) {
return ConstantPool.EMPTY_STRINGS;
} else {
return str.split(",");
}
}
/**
* 該搜索搜索
*
* @param pageNo 開始頁碼
* @param pageSize 頁大小
* @param keyword 不為空 !!!must!!!
* @param index 索引串列
* @param must 欄位串列:必須匹配
* @param should 欄位串列:應匹配
* @param type 默認為 text
* @return HashMap<String, List < Object>> indexName -> 該index下的所有的搜索結果
*/
public HashMap<String, List<Object>> search(String keyword, Integer pageNo, Integer pageSize, String type,
String index, String must, String should, Boolean isHighlight) {
return searchBuild(
keyword,
pageNo == null ? 0 : pageNo,
pageSize == null ? config.getDefaultPageSize() : pageSize,
type == null ? "text" : type,
sp(index),
sp(must),
sp(should),
isHighlight
);
}
@SneakyThrows
@SuppressWarnings("all")
private HashMap<String, List<Object>> searchBuild(String keyword, int pageNo, int pageSize, String type,
String[] indices, String[] must, String[] should, Boolean isHighlight) {
log.info("pageNo: {} | pageSize: {} | keyword: {} | indices: {} | must: {} | should: {} | type: {}",
pageNo, pageSize, keyword, indices, must, should, type);
if (keyword == null || keyword.trim().equals("")) return ConstantPool.EMPTY_HASH_MAP;
if (indices.length == 0) {
indices = allIndex;
} else {
indices = Arrays.stream(indices)
.filter(v1 -> Arrays.asList(allIndex).contains(v1))
.toArray(String[]::new);
if (indices.length == 0) {
return ConstantPool.EMPTY_HASH_MAP;
}
}
SearchRequest request = new SearchRequest(indices);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
HighlightBuilder highlightBuilder = new HighlightBuilder();
BoolQueryBuilder query = QueryBuilders.boolQuery();
if (0 == must.length && 0 == should.length) {
HashSet<String> set = new HashSet<>();
for (String index : indices) {
typeFieldMix.get(index).get(type).forEach(name -> {
set.add(name);
});
}
set.forEach(name -> {
query.should(QueryBuilders.matchQuery(name, keyword));
highlightBuilder.field(name);
});
} else {
for (String name : must) {
query.must(QueryBuilders.matchQuery(name, keyword));
highlightBuilder.field(name);
}
for (String name : should) {
query.should(QueryBuilders.matchQuery(name, keyword));
highlightBuilder.field(name);
}
}
if (isHighlight != null && isHighlight) {
highlightBuilder.preTags(config.getPreTags());
highlightBuilder.postTags(config.getPostTags());
searchSourceBuilder.highlighter(highlightBuilder);
}
SearchRequest searchRequest = request.source(
searchSourceBuilder
.query(query)
.from(pageNo)
.size(pageSize)
.timeout(new TimeValue(60, TimeUnit.SECONDS))
);
// 并且回傳格式化資料,score排序
SearchHit[] hits = client.search(searchRequest, RequestOptions.DEFAULT).getHits().getHits();
HashMap<String, List<Object>> dataMap = new HashMap<>();
for (String index : indices) {
dataMap.put(index, new ArrayList<>());
}
if (isHighlight != null && isHighlight) {
for (SearchHit hit : hits) {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
for (Map.Entry<String, HighlightField> entry : hit.getHighlightFields().entrySet()) {
sourceAsMap.put(entry.getKey(), entry.getValue().fragments()[0].toString());
}
sourceAsMap.put("id", hit.getId());
dataMap.get(hit.getIndex()).add(sourceAsMap);
}
} else {
for (SearchHit hit : hits) {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
sourceAsMap.put("id", hit.getId());
dataMap.get(hit.getIndex()).add(sourceAsMap);
}
}
dataMap.keySet().removeIf(key -> dataMap.get(key).size() == 0);
return dataMap;
}
public HashMap<String, List<Object>> list(Integer pageNo, Integer pageSize, String index, String sortName, String order) {
return listBuild(
pageNo == null ? 0 : pageNo,
pageSize == null ? config.getDefaultPageSize() : pageSize,
sp(index),
sortName,
"asc".equalsIgnoreCase(order) ? SortOrder.ASC : SortOrder.DESC
);
}
@SneakyThrows
@SuppressWarnings("all")
private HashMap<String, List<Object>> listBuild(int pageNo, int pageSize, String[] indices, String sortName, SortOrder order) {
log.info("list -> pageNo: {} | pageSize: {} | indices: {}", pageNo, pageSize, indices);
if (indices.length == 0) {
indices = allIndex;
} else {
indices = Arrays.stream(indices)
.filter(v1 -> Arrays.asList(allIndex).contains(v1))
.toArray(String[]::new);
if (indices.length == 0) {
return ConstantPool.EMPTY_HASH_MAP;
}
}
SearchRequest request = new SearchRequest(indices);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
if (sortName != null) {
if (order != null) {
searchSourceBuilder.sort(sortName, order);
} else {
searchSourceBuilder.sort(sortName, SortOrder.DESC);
}
}
MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
SearchRequest searchRequest = request.source(
searchSourceBuilder
.query(matchAllQueryBuilder)
.from(pageNo)
.size(pageSize)
.timeout(new TimeValue(60, TimeUnit.SECONDS))
);
// 增加高亮,并且回傳格式化資料,score排序
SearchHit[] hits = client.search(searchRequest, RequestOptions.DEFAULT).getHits().getHits();
HashMap<String, List<Object>> dataMap = new HashMap<>();
for (String index : indices) {
dataMap.put(index, new ArrayList<>());
}
for (SearchHit hit : hits) {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
sourceAsMap.put("id", hit.getId());
dataMap.get(hit.getIndex()).add(sourceAsMap);
}
dataMap.keySet().removeIf(key -> dataMap.get(key).size() == 0);
return dataMap;
}
@SneakyThrows
private void initIndex() {
Set<Class<?>> classSet = ClassUtil.getClassSet(config.getPkg()); // 獲得該包下的所有類
for (Class<?> aClass : classSet) {
Index index = aClass.getDeclaredAnnotation(Index.class);
if (index != null) { // 設定indexName
String indexName = "";
if (!index.value().equals("")) {
indexName = index.value();
} else {
indexName = humpToLine(aClass.getSimpleName());
}
indexMap.put(aClass.getName(), indexName);
HashMap<String, List<String>> typeListMap = new HashMap<>();
for (String s : esTypes) {
typeListMap.put(s, new ArrayList<>());
}
HashMap<String, Field> map = new HashMap<>();
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
if (field.isAnnotationPresent(IndexId.class)) {
field.setAccessible(true);
indexIdMap.put(indexName, field);
continue;
}
IndexField indexField = field.getAnnotation(IndexField.class);
if (indexField != null) {
String fieldName = "";
field.setAccessible(true);
if (!indexField.value().equals("")) {
fieldName = indexField.value();
} else {
fieldName = humpToLine(field.getName());
}
map.put(fieldName, field);
if (indexField.isSearch()) {
typeListMap.get(parseType(field)).add(fieldName);
}
}
}
typeFieldMix.put(indexName, typeListMap);
indexFiledMap.put(indexName, map);
// 判斷是否存在
if (!isExistIndex(aClass)) {
createIndex(aClass);
log.info("auto createIndex {} in ElasticSearchService", indexName);
} else {
updateIndex(aClass);
log.info("auto updateIndex {} in ElasticSearchService", indexName);
}
}
}
String[] split = dateFormat.split("\\|\\|");
simpleDateFormat = new SimpleDateFormat(split[0]);
allIndex = indexFiledMap.keySet().toArray(ConstantPool.EMPTY_STRINGS);
log.debug("initIndexMap=>{}", indexMap);
log.debug("initIndexIdMap=>{}", indexIdMap);
log.debug("initIndexFiledMap=>{}", indexFiledMap);
log.debug("initTypeFieldMix=>{}", typeFieldMix);
}
@Data
private class Meta {
private String indexName;
private String indexId;
private final Map<String, Object> source = new HashMap<>();
@SneakyThrows
public Meta(Object o) {
String className = o.getClass().getName();
indexName = indexMap.get(className);
Map<String, Field> fieldMap = indexFiledMap.get(indexName);
Field indexIdField = indexIdMap.get(indexName);
if (indexIdField != null) {
indexId = indexIdField.get(o) == null ? "" : indexIdField.get(o) + "";
} else {
indexId = "";
}
for (Map.Entry<String, Field> entry : fieldMap.entrySet()) {
Field field = entry.getValue();
Object value = field.get(o);
if (value == null) continue;
if (value.getClass().getTypeName().equals("java.util.Date")) {
value = simpleDateFormat.format(value);
}
IndexField indexField = field.getAnnotation(IndexField.class);
if (indexField.value().equals("")) {
source.put(field.getName(), value);
} else { // 如果有別名,則設定為別名
source.put(indexField.value(), value);
}
}
}
}
public static String humpToLine(String str) {
Matcher matcher = humpPattern.matcher(str);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
}
matcher.appendTail(sb);
if (sb.charAt(0) == '_') {
return sb.substring(1);
}
return sb.toString();
}
/**
* 用于測驗初始化,初始化時會生成所有的索引
*/
public void runInit() {
// initIndex();
}
}
代碼有點長,你們忍一下,,,
最后附上地址 https://gitee.com/iozxc/smart-es
另外另一個專案,一個輕量級的權限專案,
Au權限框架 是基于Springboot的一款權限認證框架,整合了RSA、JWT,使用了RBAC模式,省去了很多繁瑣的配置、使用非常簡單,
https://blog.csdn.net/qq_42883292/article/details/119686717
https://gitee.com/iozxc/au
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/294156.html
標籤:其他
上一篇:ELK日志分析系統(未完...)
下一篇:史上最全 RabbitMQ入門教程,從零開始帶你深入♂學習(九)——Routing 之訂閱模型-Direct(直連)
