Java注解(4):一个真实的Elasticsearch案例

昨天把拼了一半的注解+Elasticsearch积木放下了,因为东西太多了拼不好,还容易乱。休息了一晚上接着来。

 

接着昨天,创建elasticsearch文档注解(相当于数据表的注解):

/**  * elastic文档注解,定义每个elasticsearch文档上的属性  *  * @author xiangwang  */ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) public @interface Document {     String index();      String type() default "_doc";      boolean useServerConfiguration() default false;      short shards() default 1;      short replicas() default 0;      String refreshInterval() default "1s";      String indexStoreType() default "fs"; }

 

然后再创建elasticsearch文档(相当于数据表):

/**  * elastic文档对象  *  * @author xiangwang  */ @Document(index = "document", type = "_doc", shards = 1, replicas = 0) public class ElasticDocument {     private static final long serialVersionUID = 2879048112350101009L;     // 文档编码     @DocField(name = "guid", type = FieldType.Keyword)     protected String guid = "";     // 标题     @DocField(name = "title", type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")     protected String title = "";     // 文档创建时间(资源实际创建时间)     @DocField(name = "createtime", type = FieldType.Long)     protected long createtime;     // 文档更新时间(资源实际更新时间)     @DocField(name = "updatetime", type = FieldType.Long)     protected long updatetime;      public ElasticDocument() {     }     public String getGuid() {         return guid;     }     public void setGuid(String guid) {         this.guid = guid;     }     public String getTitle() {         return title;     }     public void setTitle(String title) {         this.title = title;     }     public long getCreatetime() {         return createtime;     }     public void setCreatetime(long createtime) {         this.createtime = createtime;     }     public long getUpdatetime() {         return updatetime;     }     public void setUpdatetime(long updatetime) {         this.updatetime = updatetime;     }     @Override     public String toString() {         return String.format("{"guid":"%s", "title":"%s", "createtime":%d, " +                         ""updatetime":%d}", guid, title, createtime, updatetime);     } }

 

这里面的@Document就是刚才创建的文档注解。

最后,创建一个真正的执行者,就由它来完成所有材料的拼装:

/**  * ElasticDao  *  * @author xiangwang  */ @Component public class ElasticDao {     // ElasticConfiguration中定义的Bean对象     @Autowired     private RestHighLevelClient client;      /**      * 索引是否存在      *      */     public boolean indexExist(final String index) {         try {             return client.indices().exists(new GetIndexRequest(index), RequestOptions.DEFAULT);         } catch (IOException e) {             System.out.println("index exist exception");         }         return false;     }      /**      * 解析类注解,获取包括父类字段在内的所有字段      * 因为解析的时候,会把父类及自身的一些额外字段给解析进去      * 如logger、serialVersionUID等      * 所以需要把这些无用的字段排除掉      * 这里不存在继承,所以直接调用clazz.getDeclaredFields()      * 另外,如果存在继承关系,该怎么处理呢?(可以思考一下)      *      */     public static List<Field> getAllDeclaredFields(Class<?> clazz) {         return new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));     }      /**      * 创建索引,前面都是为了实现它作准备      * 这里会通过注解,一路解析文档的字段,拼接成可执行的脚本交给elasticsearch的api去执行      *      */     public boolean createIndex(final String index, final Class<?> clazz) {         try {             Document document = (Document) clazz.getAnnotation(Document.class);             int shards = document.shards();             int replicas = document.replicas();             if (indexExist(index)) {                 return false;             }              CreateIndexRequest request = new CreateIndexRequest(index);             request.settings(Settings.builder()                     .put("index.number_of_shards", shards)                     .put("index.number_of_replicas", replicas)             );             StringBuilder builder = new StringBuilder();             builder.append("{n");             builder.append("   "properties": {n");              List<Field> list = getAllDeclaredFields(clazz);             int length = list.size();             for (int i = 0; i < length; i++) {                 DocField docField = list.get(i).getAnnotation(DocField.class);                 if (null == docField) {                     continue;                 }                 builder.append("      "").append(docField.name()).append("" : {n");                 builder.append("         "type" : "").append(docField.type().value).append(""");                 if (docField.index()) {                     builder.append(", n");                     builder.append("         "index" : ").append(docField.index());                 }                 if (docField.fielddata()) {                     builder.append(", n");                     builder.append("         "fielddata" : ").append(docField.fielddata());                 }                 if (docField.store()) {                     builder.append(", n");                     builder.append("         "store" : ").append(docField.store());                 }                 if (StringUtils.isNotBlank(docField.analyzer())) {                     builder.append(", n");                     builder.append("         "analyzer" : "").append(docField.analyzer()).append(""");                 }                 if (StringUtils.isNotBlank(docField.format())) {                     builder.append(", n");                     builder.append("         "format" : "").append(docField.format()).append(""");                 }                 if (StringUtils.isNotBlank(docField.searchAnalyzer())) {                     builder.append(", n");                     builder.append("         "search_analyzer" : "").append(docField.searchAnalyzer()).append(""");                 }                 if (StringUtils.isNotBlank(docField.pattern())) {                     builder.append(", n");                     builder.append("         "pattern" : "").append(docField.pattern()).append(""");                 }                 if (StringUtils.isNotBlank(docField.normalizer())) {                     builder.append(", n");                     builder.append("         "normalizer" : "").append(docField.normalizer()).append(""");                 }                 if (i == length -1) {                     builder.append("n      }n");                 } else {                     builder.append("n      }, n");                 }             }             builder.append("   }n");             builder.append("}n");             request.mapping(JSON.parseObject(builder.toString()).toJSONString(), XContentType.JSON);             CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);             boolean acknowledged = response.isAcknowledged();             return acknowledged;         } catch (IOException e) {             System.out.println("create index exception");         }         return false;     } }

 

好了,现在该搭个台子让这个执行者上台表演了:

/**  * 索引Service实现  *  * @author xiangwang  */ @Service public class IndexService {     @Resource     private ElasticDao elasticDao;      /**      * 索引初始化      *      * 这个方法可以在启动应用时调用,可以在接口中调用,也可以在main方法中调用      */     @PostConstruct     private void initIndex() {         boolean flag = false;         // 创建一个名为Test的索引         if (!elasticDao.indexExist("Test")) {             flag = elasticDao.createIndex("Test", ElasticDocument.class);             if (flag) {                 System.out.println("create Test index success");             } else {                 System.out.println("create Test index failure");             }         } else {             System.out.println("Test index exist");         }     } }

 

这就是整个注解结合Elasticsearch的真实案例。

其实这玩意一开始只是作为代码里面的小工具,但到后来随着需求越来越多,越来越变态,在我们后来的系统中它发展成了一个内部的小系统,可以通过管理后台的功能按钮来动态创建、修改、删除Elasticsearch的索引和文档,以及导出、导入数据等等功能,既非常强大,也非常方便。

我想,那些目前主流开发的框架也都是这么从小做起,一点点发展起来的吧。

 

发表评论

相关文章