elasticsearch项目踩坑记

最近本人在公司做了一个关于es的项目,即将部分数据量较大的功能从MySQL关系型数据库迁移到es上面。过程也是一把辛酸泪,现把这块相关的知识记录下来,做个备忘,也给他人提一下醒。

数据格式设计

设计es的index和type的时候,首先要抛开关系型数据库的那种join表查询的概念,要么使用内嵌文档、要么使用父子文档。父子文档的使用前提是父文档数量较少而子文档数量非常多。举个例子,主机组和主机之间,由于项目里面主机的数量本来就很少,预计最多就管理1万台,所以主机组和主机就使用内嵌文档的格式,另一个是主机和主机的巡检记录,由于记录是每天都会产生的大量的数据,所以主机和巡检记录使用的是父子文档。
另外一点是设计index的时候,同一个index里面的type的字段,如果类型一致的话尽可能重名,比如user这个type里面的name代表名字,属于字符串类型,user_group这个type里面的name代表组名称,也是属于字符串类型。这个是因为es会把同一个index的字段全部合并,做成一个索引,因此如果太多的字段而且数据比较稀疏的时候,会影响查询的效率。
这第一个坑就是MySQL里面有些查询join了非常多的表,看起来头昏脑涨,后面我们就是根据表可能达到的数据量大小,分别将这些join的表用内嵌和父子重新组合,拆分出了几个index和type,即数据量小用内嵌,数据量大用父子。然后查询的时候可以分步骤查询出结果,然后进行组装结果返回给前端。

数据操作

1) es的数据操作是近实时的,数据从写入到可以被搜索,默认是1秒。这里就出现一个坑就是,你修改一条数据,比如你修改了用户名,但是重新查询之后发现并没有修改成功,但是一会之后就又可以了,这个就郁闷了。
解决办法就是设置一下你这个修改操作的策略,使用实时策略:

    UpdateRequest updateRequest = new UpdateRequest("index", "type","id")
                    .parent("pid")//有父ID记得带上,否则修改也是找不到该记录的
                    .doc(...).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);

2)写入内嵌文档的坑,以用户为主的type,如果是一一对应的内嵌文档,比如一个用户只属于一种类型,则使用Map,如果是一对多的内嵌文档,比如一个用户属于多个用户组的,则使用Object[]。
代码如下:

    Map typeMap = new HashMap<>();
                typeMap.put("name", "类型1");
                typeMap.put("id", 1);
        Object[] groupArr = new Object[3];
                for (int i = 0; i < 3; i++) {
                    Map groupMap = new HashMap<>();
                    groupMap.put("name", "用户组"+i);
                    groupMap.put("id", i);
                    groupArr[i] = groupMap;
                }
       XContentFactory.jsonBuilder()
                        .startObject()
                        .field("name", "张三")
                        .field("sex", "男")
                        .field("type", typeMap)
                        .field("groups", groupArr)
                        .endObject();

数据查询

1) es的查询参数限制,默认是限制只能传入1024个参数,比如你使用terms查询,然后传入了一串id,结果直接就报错了,这个是很坑的,因为我们将join的表拆开之后分别查询就会出现上一步的查询结果要作为参数传入给下一步的查询,比如先查询出来主机的id串,然后再去查询这些主机的巡检记录。
解决办法是在es集群的每个节点的elasticsearch.yml加上这个配置: indices.query.bool.max_clause_count: 102400
后面的数字就是你预估最大的传入参数数量了。(PS:网上有很多说是index.query.bool.max_clause_count: 102400,但据我实践是错的,我的es版本是5.4.1,可能是他们版本比较旧吧)

2) es的深分页限制,默认是最大查询1万页。这个算是一个隐藏的坑,当然推荐的是通过前端重新设计,不让出现深分页,比如通过增加条件,只能查询最近一个月的数据,限制数据量不超过1万页。然后再加上我们在创建index的时候也增加查询分页的上限,就可以彻底解决这个问题。
代码如下:

    client.admin().indices().prepareCreate(index)
                    .setSettings(Settings.builder()
                            .put("index.number_of_shards", 18)
                            .put("index.number_of_replicas", 1)
                            .put("index.max_result_window", 100000000)

暂时只想到这些,以后发现了再补充。

你可能感兴趣的:(elasticsearch,数据库)