ReIndexHelper.java 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. package com.zswl.dataservice.helper;
  2. import com.zswl.dataservice.domain.SuperEntity;
  3. import com.zswl.dataservice.utils.bean.BeanUtil;
  4. import lombok.SneakyThrows;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.apache.commons.lang3.reflect.FieldUtils;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.data.domain.Sort;
  9. import org.springframework.data.mongodb.core.MongoTemplate;
  10. import org.springframework.data.mongodb.core.index.Index;
  11. import org.springframework.data.mongodb.core.index.IndexInfo;
  12. import org.springframework.data.mongodb.core.index.IndexOperations;
  13. import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
  14. import org.springframework.stereotype.Component;
  15. import java.lang.reflect.Field;
  16. import java.util.*;
  17. import java.util.stream.Collectors;
  18. /**
  19. * 重置索引
  20. */
  21. @Slf4j
  22. @Component
  23. public class ReIndexHelper {
  24. @Autowired
  25. private MongoTemplate mongoTemplate;
  26. //每个索引里最大数量
  27. private final static int MaxIndexCount = 24;
  28. /**
  29. * 重建索引
  30. */
  31. public void reIndexFromField(Class<? extends SuperEntity> entityClass, String fieldName, Class<?> cls) {
  32. //构建索引
  33. Set<Index> nowIndexNames = BeanUtil.readBeanType(cls).keySet()
  34. .stream()
  35. .map((it) -> {
  36. final String indexName = fieldName + "." + it;
  37. return new Index().named(indexName).on(indexName, Sort.Direction.ASC);
  38. }).collect(Collectors.toSet());
  39. //更新索引
  40. updateIndex(entityClass, fieldName, nowIndexNames.toArray(new Index[0]));
  41. }
  42. /**
  43. * 重置索引
  44. */
  45. public void reIndexFromMap(Class<? extends SuperEntity> entityClass, String fieldName) {
  46. //构建索引
  47. Set<Index> nowIndexNames = getIndexNamesFromMap(entityClass, fieldName)
  48. .stream()
  49. .map((it) -> {
  50. final String indexName = fieldName + "." + it;
  51. return new Index().named(indexName).on(indexName, Sort.Direction.ASC);
  52. }).collect(Collectors.toSet());
  53. //更新索引
  54. updateIndex(entityClass, fieldName, nowIndexNames.toArray(new Index[0]));
  55. }
  56. /**
  57. * 取出现有点索引
  58. *
  59. * @return
  60. */
  61. public Set<String> getIndexNames(String tableName) {
  62. //现有索引
  63. return this.mongoTemplate.indexOps(tableName)
  64. .getIndexInfo()
  65. .stream()
  66. .map((it) -> {
  67. return it.getName();
  68. }).collect(Collectors.toSet());
  69. }
  70. public void copyIndex(String tableName, String newTableName) {
  71. final IndexOperations indexOperations = this.mongoTemplate.indexOps(tableName);
  72. indexOperations.getIndexInfo().stream().filter(it -> !Set.of("_id_", "_id").contains(it.getName())).forEach((indexInfo) -> {
  73. final String indexName = indexInfo.getName();
  74. final IndexOperations newIndexOperations = this.mongoTemplate.indexOps(newTableName);
  75. //删除索引
  76. newIndexOperations.getIndexInfo().stream().filter(it -> indexName.equals(it.getName())).forEach((it) -> {
  77. newIndexOperations.dropIndex(it.getName());
  78. });
  79. final Index newIndex = new Index();
  80. newIndex.named(indexName);
  81. indexInfo.getIndexFields().forEach((it) -> {
  82. newIndex.on(it.getKey(), it.getDirection());
  83. });
  84. //创建索引
  85. newIndexOperations.ensureIndex(newIndex);
  86. });
  87. }
  88. /**
  89. * 取出现有点索引
  90. *
  91. * @param entityClass
  92. * @return
  93. */
  94. public Set<String> getIndexNames(Class<? extends SuperEntity> entityClass) {
  95. return this.getIndexNames(this.mongoTemplate.getCollectionName(entityClass));
  96. }
  97. /**
  98. * 更新索引
  99. *
  100. * @param tableName
  101. * @param indexs
  102. */
  103. @SneakyThrows
  104. public void updateIndex(String tableName, Index... indexs) {
  105. //现有索引
  106. final Set<String> nowIndexNames = getIndexNames(tableName);
  107. //索引
  108. final IndexOperations indexOperations = this.mongoTemplate.indexOps(tableName);
  109. //索引不存在建索引
  110. Arrays.stream(indexs).filter(it -> it.getIndexKeys().size() > 0).forEach((it) -> {
  111. String indexName = getIndexName(it);
  112. if ((nowIndexNames.contains(indexName))) {
  113. indexOperations.dropIndex(indexName);
  114. }
  115. String ret = indexOperations.ensureIndex(it);
  116. log.info("update index : " + ret);
  117. });
  118. }
  119. @SneakyThrows
  120. private String getIndexName(Index index) {
  121. final Field field = FieldUtils.getDeclaredField(Index.class, "name", true);
  122. if (field == null) {
  123. return null;
  124. }
  125. Object val = field.get(index);
  126. if (val == null) {
  127. return null;
  128. }
  129. return String.valueOf(val);
  130. }
  131. /**
  132. * 更新索引,独立的索引项
  133. *
  134. * @param entityClass
  135. * @param indexs
  136. */
  137. @SneakyThrows
  138. public void updateIndex(Class<? extends SuperEntity> entityClass, Index... indexs) {
  139. this.updateIndex(this.mongoTemplate.getCollectionName(entityClass), indexs);
  140. }
  141. /**
  142. * 更新索引,共用一个索引项
  143. *
  144. * @param entityClass
  145. */
  146. @SneakyThrows
  147. public void updateIndex(Class<? extends SuperEntity> entityClass, String indexName, Index... indexs) {
  148. boolean isUpdate = false;
  149. List<IndexInfo> indexInfos = this.mongoTemplate.indexOps(entityClass)
  150. .getIndexInfo()
  151. .stream()
  152. .filter((it) -> {
  153. return it.getName().length() > indexName.length() + 1 && it.getName().substring(0, indexName.length()).equals(indexName);
  154. }).collect(Collectors.toList());
  155. if (indexInfos != null && indexInfos.size() > 0) {
  156. isUpdate = isNeedUpdateIndex(indexInfos, indexs);
  157. } else {
  158. isUpdate = true;
  159. }
  160. //进行更新索引
  161. if (isUpdate) {
  162. final IndexOperations indexOperations = this.mongoTemplate.indexOps(entityClass);
  163. //如果存在则删除所有的和符合索引
  164. indexOperations.getIndexInfo().stream().filter((it) -> {
  165. return it.getName().length() > indexName.length() + 1 && it.getName().substring(0, indexName.length()).equals(indexName);
  166. }).forEach((it) -> {
  167. indexOperations.dropIndex(it.getName());
  168. });
  169. int size = (int) (indexs.length / MaxIndexCount);
  170. for (int i = 0; i < size; i++) {
  171. updateIndex(indexOperations, indexName + "_" + i, i, indexs);
  172. }
  173. if (indexs.length % MaxIndexCount != 0) {
  174. updateIndex(indexOperations, indexName + "_" + size, size, indexs);
  175. }
  176. }
  177. }
  178. @SneakyThrows
  179. private void updateIndex(IndexOperations indexOperations, String indexName, int page, final Index[] indexs) {
  180. Index index = new Index();
  181. index.named(indexName);
  182. for (int j = 0; j < MaxIndexCount; j++) {
  183. //索引
  184. int i = page * MaxIndexCount + j;
  185. if (i >= indexs.length) {
  186. continue;
  187. }
  188. Index it = indexs[i];
  189. Field field = it.getClass().getDeclaredField("name");
  190. field.setAccessible(true);
  191. String fieldName = String.valueOf(field.get(it));
  192. index.on(fieldName, Sort.Direction.ASC);
  193. }
  194. log.info("update index : {}", indexName);
  195. indexOperations.ensureIndex(index);
  196. }
  197. /**
  198. * 需要更新的名字
  199. *
  200. * @return
  201. */
  202. private boolean isNeedUpdateIndex(List<IndexInfo> indexInfos, Index[] indexs) {
  203. //取出需要更新的索引名
  204. Set<String> newUpdateNames = Arrays.stream(indexs).map((it) -> {
  205. return it.getIndexOptions().get("name");
  206. }).filter((it) -> {
  207. return it != null;
  208. }).map((it) -> {
  209. return String.valueOf(it);
  210. }).collect(Collectors.toSet());
  211. //取出现有的索引名
  212. Set<String> nowIndexName = new HashSet<>();
  213. indexInfos.forEach((it) -> {
  214. nowIndexName.addAll(it.getIndexFields().stream().map((index) -> {
  215. return index.getKey();
  216. }).collect(Collectors.toSet()));
  217. });
  218. for (String updateName : newUpdateNames) {
  219. if (!nowIndexName.contains(updateName)) {
  220. return true;
  221. }
  222. }
  223. return false;
  224. }
  225. /**
  226. * 取出Map属性对应的所有key的集合
  227. *
  228. * @return
  229. */
  230. public Set<String> getIndexNamesFromMap(Class<? extends SuperEntity> entityClass, String fieldName) {
  231. String collectionName = this.mongoTemplate.getCollectionName(entityClass);
  232. String map = "function(){if(this." + fieldName + "==null){return}for(var key in this." + fieldName + "){emit(key,1)}};";
  233. String reduce = "function(key,values){return values.length};";
  234. Set<String> indexNames = new HashSet<>();
  235. MapReduceResults<Map> mapReduceResults = this.mongoTemplate.mapReduce(collectionName, map, reduce, Map.class);
  236. mapReduceResults.forEach((it) -> {
  237. indexNames.add(String.valueOf(it.get("_id")));
  238. });
  239. return indexNames;
  240. }
  241. }