问答
温馨提示
在框架使用中,难免会因为各种原因导致异常,我们不排除框架本身有缺陷(通常小于0.1%)导致,但目前发布的功能中,都是稳定且有测试用例覆盖及大量用户生产环境验证过的,更多的时候是依赖不兼容或用户没有按文档使用,自由发挥,导致出现一些问题,这类用户通常还比较懒,一碰到鸡毛大点问题马上来群里问,或是抱怨框架垃圾,然后我们协助排查解决最后发现是xx地方没有按文档使用,而是胡乱搞,我们也很无奈,毕竟做开源,精力和时间也比较有限,我们想把时间花在刀刃上,比如收集真正的bug,去迭代解决,而不是把时间浪费在这些无谓的地方. 所以我们还是希望用户能在使用前多读文档,遇到问题不妨先从文档下手,看看我们提供的高频问答中是否有您想问的问题,看看我们提供的DEMO是怎么写的?DEMO中实际依赖的es,fastjson,springboot版本是多少,不妨先把你项目中的依赖版本与demo中保持一致,排除依赖原因. 如仍未解决可以打断点找找原因,看看源码分析分析,经历了这些步骤,如果仍然解决不了,可以再来答疑群里问,这是一个码农基本的素养,而且对提升自身技术水平有很大帮助,如果碰到问题就抛出去,久而久之,自我独立解决和分析问题的能力会越来越差,长此以往,若有一天用了某款开源产品,碰到问题恰好没人答疑,又当何去何从?
1.当碰到有一些需求EE提供的API不支持时怎么办? 没关系,作者早就帮主公们想到最优的解决方案了,请查看这里:混合查询
2.试用过程中,报错:java.lang.reflect.UndeclaredThrowableException
Caused by: [daily_document] ElasticsearchStatusException[Elasticsearch exception [type=index_not_found_exception, reason=no such index [daily_document]]]
如果您的错误信息和原因与上面一致,请检查索引名称是否正确配置,检查全局配置,注解配置,如果配置无误,可能是索引不存在,您可以通过es-head可视化工具查看是否已存在指定索引,若无此索引,可以通过EE提供的API快速创建.
3.依赖冲突
尽管EE框架足够轻量,我在研发过程中也尽量避免使用过多其它依赖,但仍难保证在极小概率下发生和宿主项目发生依赖冲突的情况,如果有依赖冲突,开发者可通过移除重复依赖或统一依赖版本号来解决,EE所有可能发生冲突的依赖如下:
<dependency>
<groupId>cn.easy-es</groupId>
<artifactId>easy-es-boot-starter</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.14.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.14.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
4.使用wrapper.eq(xx::getXX,"查询内容")查不出来数据? eq对应的是es的TermQuery(),需要被查询字段的索引类型为keyword时才能查询,如果被查询字段的索引类型为text,那么该字段将无法被eq查询,在使用前不妨先看看自己的需求,是否需要分词匹配,如果需要分词匹配,把该字段的索引类型建立为text类型,然后使用wrapper.match(),wrapper.queryString()等方式查询;如果需要精确匹配,可将该索引字段类型建立为keyword类型,然后使用wrapper.eq()查询; 如果同一个字段,既需要用精确匹配查询,又需要被分词查询,可将其索引类型创建为keyword&text类型,在把它当作keyword类型查询时,需要传入字段名称为“字段名称.keyword”,在把它当text类型查询时,直接用字段名即可。或者不妨将该字段冗余,新增一个字段,值与该字段保持一致,一个索引用keyword,一个用text类型,这样就可以完美化解了,对es而言支持PB级数据,增加一个冗余字段,对性能影响微乎其微.
5.process index exception,java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero es单机版的配置的问题所致,并非框架原因.
6.新增数据时报错 java.lang.reflect.UndeclaredThrowableException: null 99%的情况是你的实体类中使用了嵌套对象,但实际该对象上的注解却指定为@IndexField(fieldType=Object)所致. 嵌套对象必须使用嵌套对象的语法,参考文档嵌套类型,剩余1%情况是你项目中实际引入的fastjson依赖版本过低/过高所导致,建议与我官方提供的demo中保持一致或与框架底层依赖的fastjson版本保持一致.
7.调用insert或insertBatch接口时,报错 the entity id must not be null 检查配置文件中全局id策略id-type是否为customize,以及@IndexId注解中的idType值是否为IdType.CUSTOMIZE,如果为此值则代表id由用户自定义传入,所以在插入数据前需要用户主动为该数据的id设置值,然后再插入.
8.项目启动时报错 java.lang.NoClassDefFoundError...AliasMetadata 具体报错内容 process index exception,java.util.concurrent.CompletionException: java.lang.BootstrapMethodError: java.lang.NoClassDefFoundError: org/elasticsearch/cluster/metadata/AliasMetadata 出现此报错信息,则说明你当前项目中实际依赖的es及Resthighlevelclient jar版本过低,建议升级为7.10+版本(推荐7.14.0,与框架底层所使用的依赖版本保持一致,兼容最佳),即可解决.
9.索引中出现的索引名带_s0或_s1后缀 无需担心,这是全自动平滑迁移零停机的必经之路,索引后缀不影响使用,框架会自动激活该新索引.关于_s0和_s1后缀,在此模式下无法避免,因为要保留原索引数据迁移,又不能同时存在两个同名索引. 其完整原理可以参考索引处理章节.
10.索引会被追加别名ee_default_alias 无需担心,每个索引都可以有N个索引别名,此别名主要用于方便框架底层对框架自动托管的索引进行管理,相当于给索引打了个标签,是追加机制,不会影响你已有索引别名,就好比你真名叫老汉,别人给你取了个外号叫猛男,叫帅哥,叫糟老头子坏得很...并不影响你的真实身份是老汉.
11.支持跨索引CRUD吗? 针对索引结构相同的情况,用户可在wrapper.index(indexName1,indexName2...)指定当前操作生效的索引,若方法无wrapper,可以直接在对应接口中传入,比如insert(entity,indexName1,indexName2...),要求索引结构必须相同才可以,否则无法执行成功, 此功能适用于索引结构是按日期生成的用户,比如按月,按年生成,只是索引名称不同,但索引结构相同,就可以通过此方案来解决CRUD中的困惑.
12.为什么通过@IndexField注解指定的索引类型为keyword(或其它类型),实际创建出来的索引类型却是下图这样,这是为啥?
- 首先你需要确认当前索引开启的是"自动挡模式",默认是开启的,如果是手动挡模式,自定义注解指定的索引类型,仅在下面这两个api中生效,对于纯自定义的场景并不会生效.
Boolean createIndex();
Boolean createIndex(String indexName);
2
因为纯自定义的场景为了保证原生的灵活性,索引的类型等所有信息均由用户自己指定,而非自定义注解.
- 其次你需要确认在自动挡模式或上述两个API进行创建索引时,是否创建成功,索引创建成功的标志是项目启动时控制台打印出 ===> Congratulations auto process index by Easy-Es is done !
如果控制台打印出===> Unfortunately, auto process index by Easy-Es failed...则说明索引托管失败了,具体原因可以看看紧随其后的日志. 不过经过这么久的社区答疑,99.99%的情况都是下面这两种原因,可供参考:
- 底层es或RestHighLevelClient依赖版本冲突了,由于EE底层用的es和RestHighLevelClient依赖版本是7.14.0,ES本身版本兼容做的又比较差,而Springboot有springdata-es,所以它内置了和es的对应版本,因此不可避免的会出现因为springboot版本不同带来的es依赖冲突,导致很多功能不兼容,进而导致索引托管失败,可以将es和RestHighLevelClient版本统一为7.14.0,不会的话请自行百度依赖冲突如何解决,这是java程序员的基本技能了,如果你还不会赶紧去学,我真的栓Q,不要再问我这种低级问题!
- 实体类中使用了嵌套类型,但未按照嵌套类型的使用文档去配置,导致索引托管失败了,很多人不知道嵌套类型是啥,简单来说就是你实体类中引入了其它自定义的对象或者Map.
- 实体类中使用了List<String|Integer等包装类型...>,此时该字段的索引类型应该定义为text而非array, 查询时可以通过wrapper.match查询,es默认分词器会通过数组中的逗号把具体数据给查出来.
那么有用户纳闷了,为啥你都说索引托管失败了,可实际上索引却是存在的,通过es-head也能看到,并且该字段的类型是keyword&text类型,这是因为在该字段不存在的情况下,如果你调用了数据插入/更新api,es本身(非easy-es)也会帮你自动创建索引,创建的索引字段类型默认就是keyword&text类型
13.为什么通过eq查不出来数据? 通过match查不出来数据 通过xxx查不出来数据? 首先你要明确eq对应的是es的termQuery,match对应的是matchQuery...具体可参考MySQLy和EE语法对比 term查询要求字段类型为keyword,matchQuery则要求字段类型为text,并且如果是中文的话需要安装中文分词器,比如ik,然后在索引中正确创建和配置,才能查询出来. 查不出来不妨先检查你的索引类型,分词器,以及分词器是否能把你输入的关键词给分出来,原文中是否能命中,存储和查询是否用的同一种分词器等都需要先确认,而不是上来就质疑框架有bug,框架已上线的功能都是有单测覆盖并且大量用户使用的,否则也不会轻易上线.