
荒腔走板
- 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 | 一行数据 |