阅读 161

Q&A服务引发的肝暴(二)

荒腔走板

  • EIP-CM 项目做完许久,再想写点科(sao)技(hua)连篇的文章就非常挣扎,甚至你都可能忘记做过哪些功能? 就好比:你拿到新的改动需求定位到相应代码的时候,脑海中冒出十万个草泥马,这谁写的代码真 TMD烂,紧接着代码正上方,注释着 this bug made in 蒋帅 ;Anyway,反正我不尴尬,尴尬的就是代码。
  • 书接上文,上回说到 Elasticsearch 的应用场景,QA 服务的难点,痛点,这篇主要聊 ES 踩过的坑以及实战。

目录:

文章宗旨:问答形式,踩坑分享

  • 1.ElasticSearch 安装的坑(切账户启动,外网访问,权限控制)
  • 2.ElasticSearch 版本选择的坑
  • 3.ElasticSearch 支持的数据结构,Object 和 NestObject 的坑
  • 4.灵活表单实体设计,Mapping 需要提前创建好不然也是坑
  • 5.具体代码打字有点累,待续。。。。

言归正传

问题一:ElasticSearch 安装的坑

  • 坑一:创建账号   注意!es 启动是不允许使用 root 账号来启动的,所以我们需要来创建一个其他的账号并赋予其账号对应权限 useradd esuser
  • 坑二:#一定要赋权限,不然又会报没权限的错误 chown -R esuser:esuser /data/elasticsearch/elasticsearch-5.6.8

#切换账号 su esuser#启动 ES ./elasticsearch &

  • 坑三:外网访问 ES 需要配置 进入配置文件 修改 network.host 为 0.0.0.0 注意!因为是 yml 文件,所以一定要注意格式。

  • 坑四:启动报错: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]

每个进程最大同时打开文件数太小,可通过下面 2 个命令查看当前数量 ulimit -Hn ulimit -Sn   修改/etc/security/limits.conf 文件,增加配置,用户退出后重新登录生效

  •           soft    nofile          65536
    复制代码
  •           hard    nofile          65536
    复制代码

ElasticSearch数据类型Object 和 NestObject 的坑

上文说道 ElasticSearch 支持的基本的数据结构,在不知道有 NestObject 这个数据结构之前我认为 Object 是可以解决一切实体问题,毕竟万物皆对象嘛! 然而戏剧性的一幕出现了。如下: 我们使用 ES 存储下面的 json 字符串

创建 mapping

插入数据

查询 age 为 37 岁,名字为 YanXi 的人,按道理说,是不是查不到?

但结果如下图:"纳尼,全给我查出来了,ES 辣鸡东西"

后来百度了一番,解释 这是因为我们上面传入的 json 文档都存为了一条文档中了,上面的插入其实被转化为:

怎么办呢?!!那就是 Nested 类型的用武之地了

查询果然查不到,结果验证正确:

ElasticSearch 版本选择的坑

1.ES 到目前为止已经有 7.X 版本,6.x 版本到 7.x 版本有很大的改变,有些功能 API 都有变动;那么问题来了,怎么选择合适的版本,是不是最新的版本越好呢,实际上我们现在的应用大多数都是用 springboot 做整合框架,那么就有好处,我这里推荐一个小技巧。 引入 data-elasticsearch 的依赖后,SpringBoot 根据 spring-boot-starter-parent 的版本号自动选择合适的 Elasticsearch 版本号。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
复制代码

这样我们就可以愉快的选择合适的 ES 版本,如果项目需要 IK 分词的话,也需要将 IK 的版本与其统一;

问题:到底怎样才算灵活 1.不得不说所有开发前期的设计都是非常挣扎的,不仅要考虑满足现有需求,同时结合实际业务量考虑后期数据的可维护性。 看在 Mysql 是程序员正寝的份上,先说说使用 Mysql 的设计

Mysql 的设计

这里只 demo 一下不是重点,前端是死页面,后端是灵活的,当然有很多设计方法 首先针对详情查询,详情编辑设计 你需要一个字段去维护所有的属性和属性值 form_data 这个字段的内容大概长这样{"name":"蒋帅","age":"16","sex":猛男}

但是这样按字段条件进行分页查询怎么做? 是不是还得建立一张针对查询字段的表,这样的设计似乎有点扯?

如果前端也不固定,则需要建立 t_field_config 表去维护所有的字段,这样在详情页你则可以将所有表单控件渲染出来

上篇文章说过如果业务字段不固定用关系型数据库 Mysql 一定是个坑。

回归正题: 类似 ElasticSearch 或者 Mysql 数据库是通过实体映射操作的,以特定的字段为驱动做索引做查询,实体内字段必须固定,这不是和灵活表单不固定字段相违背吗,所以我们是不是需要找到共性呢,就好比每个人虽然是是不一样,但是总有眼睛,鼻子,嘴巴对吧,那回归设计,是不是一个表单的字段一般都会有字段英文属性名,字段中文别名,字段值呢,我们基于这个思路走下去。

既然这样,我们就设计下实体,简单来说想做通用模块,就必须衔接各个应用系统,所以使用 appid 来区分应用,使用模块 id 来区分应用中的功能模块,当然包括公用字段创建修改的时间,人,是否删除,废话不多说,直接贴代码

@Document(indexName = "qaindex"type = "qatype")
public class QAEsCommonModel{
    @Id
    private Long id;
    //应用
    @Field(type = FieldType.keyword)
    private String appId;
    //模块
    @Field(type = FieldType.keyword)
    private String moduleId;

    @Field(type = FieldType.keyword)
    private String createName;

    @Field(type = FieldType.keyword)
    private String createTime;

    @Field(type = FieldType.keyword)
    private Integer isDeleted;

    //灵活字段集合
    @Field(type = FieldType.Nested)
    private List<CommonParam> commonParamList;
}
复制代码
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class CommonParam {
    /**
     *字段名  如:sex
     */
    @Field(type = FieldType.keyword)
    private String property;

    /**
     *字段别名 如:性别
     */
    @Field(type = FieldType.keyword)
    private String alias;

    /**
     *字段值(需要分词,需要参与全文索引的 如:标题,答案等)
     */
    @Field(analyzer = "ik_max_word",type = FieldType.text)
    private String textValue;

    /**
     *字段值(不需要分词)
     */
    @Field(type = FieldType.keyword)
    private String keywordValue;
}
复制代码

这里又涉及到几个 ES 的知识点,结合 Mysql 对比下 @Document(indexName = "qaindex", type = "qatype")

  • qaindex:数据库
  • qatype :表 这里的字段类型要注意的是不需要分词的用 keyword,需要分词的用 Text 类型 ElasticSearchMysqlindex 数据库 type 数据表 docuemnt 一行数据
ElasticSearch Mysql
index 数据库
type 数据表
docuemnt 一行数据
文章分类
后端