Elaticsearch,即es,是一个开源的高扩展的分布式全文检索引擎,可以近乎实时的存储、检索数据;具备良好的扩展性,可以扩展到上百台服务器,足以处理PB级别(大数据时代)的数据。es也使用java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
es的安装就不再赘述了,用docker可以快速安装。但是需要修改某些配置。本文重点围绕elasticsearch的一些概念性的东西和使用过程中应该注意的点。
- ElasticSearch核心概念
elasticsearch(集群)中可以包含多个索引(数据库) ,每个索引中可以包含多个类型(表) ,每个类型下又包含多个文档(行) ,每个文档中又包含多个字段(列),具体对比见下表:
Relational DB | ElasticSearch |
数据库(database) | 索引(indices) |
表(tables) | types |
行(rows) | documents |
字段(columns) | fields |
一开始不理解为什么types会和关系型数据库里的表相对应,但在实际使用elasticsearch的过程中体会到了为什么会用types。比如我们在一个索引库中想存一些文章,那么在关系型数据库中我们一般就会创建一个“文章”表,如果想再在索引库中存一些作者,那么我们相应的也会在关系型数据库中创建一个“作者”表,那么实际上“文章”、“作者”就是不同的类型,即不同的“type”。
- 分词器插件
所谓分词就是把一段中文或者别的语言的一段话划分成一个个的关键字,在ES中存入数据的时候会分词,在查询索引是ES也会对输入的查询语句进行分词,然后进行匹配。不使用IK分词器的情况下默认的中文分词是将每个字看成一个词,比如“我爱小芳”会被分为”我”,”爱”,”小”,”芳” ,这显然是不符合要求的,所以我们需要安装中文分词器ik来解决这个问题。
ik提供了两个分词算法: ik_smart和ik_max_word ,其中ik_smart为最少切分, ik_max_word为最细粒度划分。
- Rest风格API
method | url地址 | 描述 |
PUT(创建,修改) | localhost:9200/索引名称/类型名称/文档id | 创建文档(指定文档id) |
POST(创建) | localhost:9200/索引名称/类型名称 | 创建文档(随机文档id) |
POST(修改) | localhost:9200/索引名称/类型名称/文档id/_update | 修改文档 |
DELETE(删除) | localhost:9200/索引名称/类型名称/文档id | 删除文档 |
GET(查询) | localhost:9200/索引名称/类型名称/文档id | 查询文档通过文档ID |
POST(查询) | localhost:9200/索引名称/类型名称/文档id/_search | 查询所有数据 |
- 创建索引
PUT /test1/type1/1
{
"name" : "张三",
"age" : 18
}
- 指定字段的类型(使用PUT)
类似于建库(建立索引和字段对应类型),也可看做规则(mapping)的建立
PUT /test2
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"age":{
"type": "long"
},
"birthday":{
"type": "date"
}
}
}
}
- 修改
- 使用put覆盖原来的值,版本(_version)会加1,但是如果漏掉某个字段没有写,那么更新时没有写的字段会消失。以下例子中更新之后“age”和“birth”这两个field会消失。
PUT /test3/_doc/1
{
"name" : "张三是我的大哥",
"age" : 18,
"birth" : "1999-10-10"
}
GET /test3/_doc/1
//修改会有字段丢失
PUT /test3/_doc/1
{
"name" : "张三是我的大哥"
}
- 使用post的update,version不会改变,不会丢失字段
POST /test3/_doc/1/_update
{
"doc":{
"name" : "post修改,version不会加一",
"age" : 2
}
}
- 删除
DELETE /test1
- 查询简单条件
GET /test3/_doc/_search?q=name:张三
- 复杂条件查询
- 匹配查询
match:匹配(会使用分词器解析(先分析文档,然后进行查询))
_source:过滤字段
sort:排序
form、size 分页
GET /blog/user/_search
{
"query":{
"match":{
"name":"张"
}
},
"_source": ["name","desc"],
"sort": [
{
"age": {
"order": "asc"
}
}
],
"from": 0,
"size": 1
}
- 多条件查询
must 相当于 and
should 相当于 or
must_not 相当于 not (... and ...)
filter 过滤
GET /blog/user/_search
{
"query":{
"bool": {
"must": [
{
"match":{
"age":3
}
},
{
"match": {
"name": "流"
}
}
],
"filter": {
"range": {
"age": {
"gte": 1,
"lte": 3
}
}
}
}
}
}
- 精确查询
精确查询(必须全部都有,而且不可分,即按一个完整的词查询)。term 直接通过 倒排索引 指定词条查询,适合查询 number、date、keyword ,不适合text。
- 高亮查询
// 高亮查询
GET blog/user/_search
{
"query": {
"match": {
"name":"流"
}
},
"highlight": {
"fields": {
"name": {}
}
}
}
// 自定义前缀和后缀
GET blog/user/_search
{
"query": {
"match": {
"name":"流"
}
},
"highlight": {
"pre_tags": "<p class='key' style='color:red'>",
"post_tags": "</p>",
"fields": {
"name": {}
}
}
}
- 聚合aggregations
聚合可以让我们极其方便的实现对数据的统计、分析。例如:什么品牌的手机最受欢迎?这些手机的平均价格、最高价格、最低价格?这些手机每月的销售情况如何?实现这些统计功能的比数据库的sql要方便的多,而且查询速度非常快,可以实现实时搜索效果。
Elasticsearch中的聚合,包含多种类型,最常用的两种,一个叫桶,一个叫度量.
桶(bucket)
桶的作用,是按照某种方式对数据进行分组,每一组数据在ES中称为一个桶,例如我们根据国籍对人划分,可以得到中国桶、英国桶,日本桶……或者我们按照年龄段对人进行划分:0~10,10~20,20~30,30~40等。
Elasticsearch中提供的划分桶的方式有很多:
Date Histogram Aggregation:根据日期阶梯分组,例如给定阶梯为周,会自动每周分为一组
Histogram Aggregation:根据数值阶梯分组,与日期类似
Terms Aggregation:根据词条内容分组,词条内容完全匹配的为一组
Range Aggregation:数值和日期的范围分组,指定开始和结束,然后按段分组
度量(metrics)
bucket aggregations 只负责对数据进行分组,并不进行计算,因此往往bucket中往往会嵌套另一种聚合:metrics aggregations即度量。分组完成以后,我们一般会对组中的数据进行聚合运算,例如求平均值、最大、最小、求和等,这些在ES中称为度量。
常用的一些度量聚合方式:
Avg Aggregation:求平均值
Max Aggregation:求最大值
Min Aggregation:求最小值
Percentiles Aggregation:求百分比
Stats Aggregation:同时返回avg、max、min、sum、count等
Sum Aggregation:求和
Top hits Aggregation:求前几
Value Count Aggregation:求总数
……
注意:在ES中,需要进行聚合、排序、过滤的字段其处理方式比较特殊,因此不能被分词。这里我们将color和make这两个文字类型的字段设置为keyword类型,这个类型不会被分词,将来就可以参与聚合。
划分桶:
按照汽车的颜色color来划分桶:
GET /cars/_search
{
"size" : 0,
"aggs" : {
"popular_colors" : {
"terms" : {
"field" : "color"
}
}
}
}
size: 查询条数,这里设置为0,因为我们不关心搜索到的数据,只关心聚合结果,提高效率
aggs:声明这是一个聚合查询,是aggregations的缩写
popular_colors:给这次聚合起一个名字,任意。
terms:划分桶的方式,这里是根据词条划分
field:划分桶的字段
桶内度量
上例查询的是每个桶里面的文档数量,但是我们需要更复杂的文档度量,我们需要告诉Elasticsearch使用哪个字段,使用何种度量方式进行运算,这些信息要嵌套在桶内,度量的运算会基于桶内的文档进行
例:为刚刚的聚合结果添加 求价格平均值的度量:
GET /cars/_search
{
"size" : 0,
"aggs" : {
"popular_colors" : {
"terms" : {
"field" : "color"
},
"aggs":{
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
maker:在嵌套的aggs下新添一个桶,叫做maker
terms:桶的划分类型依然是词条
filed:这里根据make字段进行划分