作为一枚每天都应当是 Swift 启动的 Swifter,也需要做一些数据分析,不得已用了一段时间的 Elasticsearch (opens new window)。
暂时没有 Demo。
个人目前对 Elasticsearch 的感觉就是:这是一个超快搜索聚合大数据工具。
世界上没有什么搜索是一层不能解决的,如果有,那就两层。
本文是对查询和聚合上的一些总结和感受。数据如何收集不是本文的重点。
一起来感受一下 Elasticsearch 设计的巧妙的语法。
查询相关都在 query
字段描述,直接查询全部:
{
"from": 0,
"size": 10,
"query": {
"match_all": {}
}
}
from
字段类似平时定义的 offset
,size
类似 limit
。以上是一个搜索全部数据的例子。
来个简单的匹配?
{
"query": {
"match": {
"name": "Tony"
}
}
}
以上是一个查询名字为 Tony 的数据。
一个拥有千亿日活 App 会有多个 Tony 用户,我们现在需要关注 18 岁的 Tony 们一些数据。 那么我们需要两个匹配条件:
Elasticsearch 为我们提供了一个 bool
参数:
{
"query": {
"bool": {
// ... 匹配条件
}
}
}
在 bool
下面可以传入各种想要的匹配条件,比如 must
、must_not
、should
。
满足所有的条件,那就匹配成功!
18 岁的 Tony 来了:
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "Tony"
}
},
{
"match": {
"age": 18
}
}
]
}
}
}
当然我们也可以关注一个年龄段的 Tony,这是 18 到 28 的 Tony:
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "Tony"
}
},
{
"range": {
"age": {
"gte": 18,
"lte": 28
}
}
}
]
}
}
}
失策,有人给小姐姐起名 Tony 了,我们需要过滤掉,增加一个 must_not
即可:
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "Tony"
}
},
{
"range": {
"age": {
"gte": 18,
"lte": 28
}
}
}
],
"must_not": [
{
"match": {
"sex": "male"
}
}
]
}
}
}
一顿分析之后我们发现 18-28 的 Tony 和 28-38 的 Mike 似乎有什么关联,我们需要一起拿出来看看。
匹配条件为:(18-28
& Tony
) | (28-38
& Mike
)。
世界上没有什么搜索是一层
bool
不能解决的,如果有,那就两层bool
。
{
"query": {
"bool": {
"minimum_should_match": 1,
"should": [
{
"bool": {
"must": [
{
"match": {
"name": "Tony"
}
},
{
"range": {
"age": {
"gte": 18,
"lte": 28
}
}
}
]
}
},
{
"bool": {
"must": [
{
"match": {
"name": "Mike"
}
},
{
"range": {
"age": {
"gte": 28,
"lte": 38
}
}
}
]
}
}
]
}
}
}
这个嵌套层数理论上可以无限层,不用担心遇到各种负载的匹配规则。 这些已经满足我常用的各种标签搜索。
预告:世界上没有什么聚合是一层不能解决的,如果有,那就两层。
我们的用户都提交了哪些心仪的发型?
{
"aggs": {
"hairstyles": { // 定义任意自己喜欢的变量名
"terms": {
"field": "hairstyle",
"size": 100 // 配置需要聚合出多少种发型,默认似乎为 10,喜欢可以直接 10000
}
}
}
}
这是一个 buckets 聚合,得到的结果为:
{
"aggregations": {
"hairstyles": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "地中海",
"doc_count": 397863
},
{
"key": "最亮",
"doc_count": 23423
},
// ...
]
}
}
}
为了设计更贴心的发型,我们需要知道每种发型是 18-28 期待的人数多还是 28-38 的人数多。
再加一层 aggs
即可:
{
"aggs": {
"hairstyles": {
"terms": {
"field": "hairstyle",
"size": 100
},
"aggs": {
"age_distribution": {
"range": {
"field": "age",
"keyed": true,
"ranges": [
{ "key": "18-28", "from": 18, "to": 28 },
{ "key": "28-38", "from": 28, "to": 38 }
]
}
}
}
}
}
}
这样我们就可以拿到 hairstyles
中每个 bucket 对应的 age_distribution
结果。