前言
主要还是工作中用到了ES,所以记录一下ES的学习
简单介绍下ES,主要原理就是整合了Lucene,利用了倒排索引的特性,将传入的数据进行分词然后去重再存储。当你输入词语,会根据词语索引到id,再通过id找出所有符合的文档进行呈现,其中可以根据你自己的需求进行对应的分词逻辑,以及打分匹配逻辑,这些就先不说得太多,让我们直接进入ES的语法学习。
前置要求:默认你已经安装好了ElasticSearch以及kibana可视化工具,为了方便描述,接下来会把ElasticSearch简称为ES
可以理解成MySQL的database的概念,索引的声明必须全部由小写字母组成,对es数据的各种操作都是通过索引来进行的
可以简单的理解成一类东西的定义,在ES7.0之前可以自定义类型,用于更细粒度的数据区分,7.0之后默认_doc类型。与索引概念可以这样理解,我声明了一个手机索引,这个索引下面又区分了很多的手机类型,比如华为,苹果等
这里可以与数据库的表结构做对标,声明字段的名称,类型,以及是否参与分词,以及文档内容存储等
就是映射里面的具体的某个字段的含义了
可以理解成MySQL中表的一条记录,一个文档就对应着表里的一条数据
ES天然支持分布式存储以及搜索,用来做高可用以及数据备份,多台ES的节点可以组成一个集群共同对外提供服务
集群中的每一个ES实例都可以理解成一个节点
节点会对索引的数据进行分布式存储,就意味着会有分片的产生,而分片中又存在主分片与副本分片的概念,主分片负责读写,副本分片负责数据备份,当然这些分片是分布在多个机器节点,方便用于高可用以及异地容灾的措施
ES的增删改查是使用的REST Ful风格的语法,可以理解成如下通用模型
操作词 /索引/类型/id
操作词指的就是PUT,POST,GET,DELETE
索引见第一点基础概念
类型见第一点基础概念
Id 这里的id可以自定义,比如你可以使用你的业务id,每一个文档都需要有一个主键Id,如果新增操作不声明id,那么会有ES自动创建一个id作为主键
下面我将会举例一个简单的例子带大家熟悉ES的语法,假设现在有一个需求,公司是做手机售卖的,现在要维护手机的数据,后续会对这批数据进行相应的调整例如新增手机或者删除手机等操作。
那么针对这个需求我们抽象出分别对应ES核心概念的数据
定义索引
首先是手机,这是一种电子产品,将来还有可能是电视机,电脑等。那么我们声明一个手机库来存储对应的手机信息,这个就对应上了ES的索引,起名为tphone
定义类型
手机里面区分很多的品牌,例如华为,苹果,oppo等等。我们给对应的不同品牌的手机挂上对应的类型,例如现在库里就两款手机,一款是oppo手机,声明类型就叫做oppo,一款是苹果手机,声明类型就叫做apple
定义映射与字段
当然每个品牌的手机都有自己的一些属性,我们先简单的定义好对应的属性,接下来以JSON格式定义属性,假设苹果跟oppo目前就这三种属性,其中的每一种属性可以理解成映射当中的一个一个的字段
{
"memory":"内存",
"size":"尺寸",
"pixel":"像素"
}
当然,ES的映射的话目前存在两种方式,一种是动态映射,不用声明字段,直接做插入,ES会自动根据插入的数据类型进行对应的格式转换,转换的逻辑以如下图为准(图待上传)
另外一种是静态映射方式,直接定义字段声明(具体的格式待上传)
有了上述的几种概念以后我们就可以开始正式的接需求了
需求一:仓库新引入华为类型的手机,手机的初始属性与库里已有oppo的属性相同,也是内存,尺寸,像素
新增数据的语法可用PUT与POST,其中PUT与POST之间的差异是,POST在操作时可以不声明ID,这个时候ES会自动的生成ID,不声明ID时,默认为Insert操作,假如声明了ID,且库中已有该ID则会修改操作。而PUT在操作时必须声明ID才能进行操作,至于执行的是新增还是修改,主要取决于库内是否已有当前操作ID
可用于新增与修改数据,具体的格式如下
//假设库里当前没有ID为1的华为手机,那么如下操作就是insert,否则是做update,update需要注意的一点是会将整个json文档都进行替换,替换成最新put的json文档形式
PUT /tphone/huawei/1
{
"memory":"内存",
"size":"尺寸",
"pixel":"像素"
}
可用于新增与修改数据,(如果类型后跟的是/_search则还可以做查询)具体的格式如下
//假设库里当前没有ID为1的华为手机,那么如下操作就是insert,否则是做update,这里的update只会对提交的相同字段进行修改,而不会影响其他未操作字段
POST /tphone/huawei/1
{
"memory":"64G",
"size":"5.2",
"pixel":"300万"
}
需求2,产品想要看看库里目前已有的华为手机的内容信息
//这里可以查出 huawei类型下的所有华为手机数据
GET /tphone/huawei/_search //相当于 select * from tphone.huawei
//假设我只想看手机内存是64G的华为手机则可以修改成如下语句
GET /tphone/huawei/_search?q=memory:"64G" //相当于 select * from tphone.huawei where memory = “64G”
需求3 ,清除ID编码为1的华为手机
DELETE /tphone/huawei/1 //相当于 delete * from tphone.huawei where id = 1
ES其实最重要的目的还是提供了海量数据的快速复杂查询,所有其实光凭第二点描述的普通的查询语句很难表述很复杂的查询,对于这个问题,ES给出了DSL的语句查询模式,可以由开发人员自由组合各种复杂条件查询进行数据筛选
不带条件查询所有数据
GET /tphone/huawei/_search
{
"query":{
"match_all":{}
}
}
查询_source中数组字段phonePhoto的size > 2的文档数据
GET /Phone/_search
{
"query": {
"bool": {
"filter": [
{
"function_score": {
"query": {
"match_all": {}
},
"functions": [
{
"script_score": {
"script": {
"source": "params._source.containsKey('phonePhoto') && params._source['phonePhoto'] != null && params._source.phonePhoto.size() > 2 ? 2 : 0"
}
}
}
],
"min_score": 1
}
}
]
}
}
}