当前位置: 首页 > 后端技术 > Java

使用elasticsearch作为唯一存储源整理

时间:2023-04-02 02:10:07 Java

之前的一个项目,在设计完系统架构后,需要使用es作为唯一存储源,记录下踩过的坑:1.首先,es不会支持事务,因此在设计架构时必须考虑到这一点。特别是生产环境一般不允许es使用脚本。更新操作是在业务Java系统内存中更新,然后刷新到es数据库,所以多个线程并发修改时,只有最后一个会更新成功(其实其他线程也更新成功,只是被覆盖了)通过最后一个线程)。解决方法是给接口的调用者加分布式锁,或者把请求放到一个保证序列化的消息队列中(比如kafka的同分区)2.es不支持映射的动态修改。在设计具体的索引时,应该分析业务需要的所有字段,哪个字段使用哪种类型。3.除非特殊情况,否则所有字段都要使用关键字类型,否则会发生灾难!!!映射索引时,一定要检查映射中是否定义了业务Java要操作的字段。比如新建一个索引,在JavaBean中定义一个Person类,有一个Stringname字段。映射的时候省略了名字,所以项目运行后,第一个插入的会映射成text类型,按照trem查询的时候,一个都找不到,或者找错数据,必须付费注意映射!!!另外需要注意的是,在项目启动的时候,首先要检查es对应的index是否存在,然后再运行项目(可以使用spring的InitializingBean接口),这样基本可以保证映射正确.@Configuration@ConfigurationProperties(prefix="elastic.search.index")publicclassElasticSearchIndexConfigimplementsInitializingBean{@OverridepublicvoidafterPropertiesSet(){//...this.checkAllIndexExist();}//...}/***服务器启动时,检查所有索引是否在*/privatevoidcheckAllIndexExist(){//判断索引,不存在则抛出异常}}4、推荐使用elasticsearch-rest-high-level-client作为Java操作es的API,虽然写起来麻烦,但是找不到数据,可以debug他组装的查询语句,然后在上面执行kibana工具平台,然后找问题,需要注意版本。5、根据条件查询时(排除模糊查询),推荐使用tremAPI。6.保存数据后,保证立即再次可见。您需要将同步刷新策略更改为:IMMEDIATE(强制刷新)。es作为分布式搜索引擎,不会将每条数据实时刷新到磁盘,而是先缓存起来,再根据策略刷新。所以改成强制刷新可以保证保存成功后数据的可见性,但是对性能影响比较大,需要根据业务来选择。/***在此请求后不要刷新。默认值。*/NONE("false"),/***强制刷新作为此请求的一部分。此刷新策略不会针对高索引或搜索吞吐量进行扩展,但有助于*为流量非常低的索引呈现一致的视图。这对测试来说很棒!*/IMMEDIATE("true"),/***保持此请求打开,直到刷新使此请求的内容对搜索可见。此刷新策略与高索引和搜索吞吐量兼容,但它会导致请求等待响应,直到刷新发生。*/WAIT_UNTIL("wait_for");7、es的批量操作不支持刷新策略,都是默认的。之所以这样,是因为bulk不知道你要操作什么类型,你要操作的数据量是多少。比如之前使用一个indexRequest,为了保证数据可见性,改策略为强制刷新,后来有批量插入的需求。如果重用这个indexRequest,会报异常,需要小心。8.es可以存储海量数据。在查询这些数据时,可以使用分页。推荐一步使用searchAfterAPI。sortValues其实理解为游标。下次查询时,es会根据这个游标来查找。publicvoidpageQuery(intage){intresultLength;对象[]sortValues=null;布尔hasLogTotal=true;做{SearchResponseresponse=this.pageQueryData(age,sortValues);SearchHit[]searchHits=response.getHits().getHits();如果(searchHits.length>0){this.processData(searchHits);intindex=searchHits.length-1;SearchHitsearchHit=searchHits[索引];sortValues=searchHit.getSortValues();}resultLength=searchHits.length;}while(resultLength>0);}privateSearchResponsepageQueryData(intage,Object[]sortValues){BoolQueryBuilderboolQueryBuild=QueryBuilders.boolQuery();QueryBuildermatchQuery=QueryBuilders.matchQuery("age",age);boolQueryBuild.must(matchQuery);SearchSourceBuilder构建器=newSearchSourceBuilder();builder.query(boolQueryBuild);builder.sort(SortBuilders.fieldSort("id").order(SortOrder.ASC));建造者.size(100);if(sortValues!=null&&sortValues.length>0){builder.searchAfter(sortValues);}SearchRequestsearchRequest=newSearchRequest("person");searchRequest.source(建造者);SearchResponse响应=null;尝试{response=restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);}catch(IOExceptione){e.printStackTrace();}返回响应;}privatevoidprocessData(SearchHit[]searchHits){//转成Java对象完成业务操作}9、es不支持像mysql那样丰富的索引,他不干这一行,但是作为唯一数据源时,有些data必须是唯一的,所以需要建立唯一的索引,比如person,需要保证每个用户的身份证号是唯一的es实际中可以使用身份证号作为id,需要注意id不支持修改,即用户ID号发生变化。需要先删除再创建,不能通过尝试更新来完成。这里有删除的逻辑,所以问这样的数据重要吗?用户是否应该关心,如果是,那么这些数据可以放在备份表中。10.有时需要同步数据。使用mysql时,可以使用binlog日志,但是使用es时,不再支持类似的同步方式,可以使用mq。11.你需要考虑数据备份的情况。一般运维会每天备份一次es,不会热备份。所以在通过各种工具链接es的时候一定要小心操作生产环境中的数据,否则当天的数据是无法恢复的!!!12、数据量大时,groupcount()查询会变慢。