本来打算至少一月一更的,结果写完第一篇后爆忙了一段时间(眼神死)...
在这个专栏里,我不会翻译官方文档。所有关于ES本身的介绍,推荐直接看英文版官方文档,或者google之。ES本身以惊人的速度在迭代,现在的中文材料很容易就跟不上最新版的节奏。特别是5.0出来之后,会有非常大的变化。
在这个专栏里,我会根据自己的实战经验,写一下Elastic Search全家桶(官方自称为Elastic Stack)的应用。从年初到现在,我个人也从ES吹,到ES与Sphinx混用,到了自造轮子的阶段。ES很好用,也有坑;ES不仅仅是一个搜索引擎,配合其全家桶,可以干更多事情。我相信,告诉大家ES可以用来干嘛,比起搬运文档要更有价值。
第二篇文章,准备写一下Elastic Search的一个经典、简单的应用场景:动态排序引擎。
举个例子,现在你做了一个UGC图床产品,需要将用户最新PO的图按某种顺序(例如时间或热度)排序展示出来。用户发了图之后,在“最新”那一页一刷新,就能看到他/她刚发的图,然后可以一直往下翻。图片可能存在不同的TAG(例如“妹子图”、“无聊图”,甚至做二级的细分)。等等,我才不是在说某网站呢,这是个很常见的需求好么!
如果你用MySQL来实现这个需求,可以是可以。不过,随着图片数量和查询请求的增加,很快就会出现性能瓶颈,产生大量的慢查询。你需要一个高性能动态排序引擎,有以下的功能:
• 动态索引,即可以随时增删查改条目;
• 排序,输入from和size(从哪到哪),根据某个数值(热度或插入时间戳),倒序排序、输出结果;
• Filter,例如根据TAG筛选图片;
假定图片是先存MySQL、再同步去ES。用MySQL存数据和保证原子性,用ES来顶查询请求。在ES里面,你可以这么设计索引结构:
{
"properties": {
"id": {
"type": "long"
},
"tags": {
"type": "string"
},
"hot": {
"type": "double"
},
"new": {
"type": "double"
},
"update_time": {
"type": "date",
"format": "epoch_second"
},
"is_searchable": {
"type": "short"
}
}
}
id:即MySQL的id,使用AUTO_INCREMENT保证唯一性。
tags:即“妹子图”、“无聊图”这样的TAG,空格隔开,确保ES默认分词器可以工作。
hot:热度数据,例如妹子图的OO数量(甚至威尔逊区间啥的)。
new:即上传时间戳。
update_time:等于new。这里是Kibana里看数用的(一定要有个date属性)。
is_searchable:0或1,默认0,1的时候才能被搜出来。用于自动鉴黄、人工去黄啥的。
每次更新数据,同步更新到ES里面,这个需求就做好了。什么,这么简单?是的,二手手游账号买号平台ES把剩下的事情都完成了。
搜的时候这么搜:
{
"from": ,
"size": 10,
"query": {
"filtered": {
"query": {
"bool": {
"must": [
{
"term": {
"tags": {
"value": "妹子图"
}
}
}
]
}
},
"filter": {
"or": [
{
"and": [
{
"term": {
"is_searchable": 1
}
}
]
}
]
}
}
},
"sort": {
"hot": {
"order": "desc"
}
}
}
稍微解释一下这个语句。query里面最简单的做法是填入`"match_all": {}`,这样可以搜所有东西出来。filter先一层or再套一层and,是便于扩展的一个写法。
这个语句,可以把TAG=“妹子图”的所有内容,按热度倒序排序(啧啧)。注意,上面的语句并非性能最佳的写法,如果妹子图非常高频,就不应用must query搜索TAG,而是应该用type或者filter来过滤。
这就是我为啥那么喜欢用Elastic Search。ES是动态索引,新插入的数据马上就可以被搜出来;强大的DSL,我能想到的查询基本都能做到。
动态排序引擎这个需求,用ES几下子就能搞定,性能还不差。