转载

简析Instgram的搜索架构

原文: Search Architecture

作者:Maxime Boucher, Thomas Dimson

翻译:孙薇

Instagram的优势在于:虽然公司规模小,却拥有相对大得多的基础设施架构,在恰当的时候还能利用资源以借助Facebook十年来积累的经验。Facebook的“Unicorn”搜索架构是一款以社交图谱为基础的搜索引擎,可扩展至包含上万亿个文档的索引。2015年初,Instagram将所有的搜索架构从Elasticsearch转到Unicorn。同一时期,Instagram的搜索流量增加了65%,这不仅是用户群数量增加的结果,也是忠实用户数(每次使用搜索引擎时都会使用Instagram)增长了12%的结果。

这样的成果部分得益于Unicorn通过社交功能及二阶连接执行查询排序的能力。在7.0升级后,通过对图谱的各个部分编制索引,Instagram的搜索能力更强,可以更迅速、更便捷地搜索任何想要查找的信息,包括人、地点、标签与媒体。

什么是搜索?

Instagram的搜索架构包含了所有兴趣实体,如:标签、位置、用户及媒体,这些内容以非规范化的形式储存,通常被称为文档——它们被分组归类到集合中,可通过高效的集合运算(如AND、OR与NOT)来查询,在实际操作中Instagram对运算结果高效地排序筛选,只留下与指定查询最相关的文档。当用户查询时,服务器后端会将查询转换成编码,进行集合运算后筛出最佳匹配结合的有序集合。

数据录入

Instagram每秒可处理数百万个搜索请求,其中很多如注册、点赞和上传在内的请求需要修改现有记录,并向主PostSQL数据库增加新行。为了确保可搜索文件的集合正确,我们需要将这些变更告知搜索架构。此外,在PostgreSQL数据库中,搜索时一般需要不只一行的信息,例如在照片上传后,该用户帐号的历史信息也会用在搜索中。

为了解决非规范化的问题,Instagram引入了Slipstream系统,该系统会对Instagram上的event进行编码,再录入包含更多信息的 Thrift 架构中。这些event以二进制序列化格式存储,通过异步发送-订阅频道(Firehose)来发送。譬如“搜索”功能之类的消费者订阅到Firehose,过滤掉不相干的event,再对其余event作出反应。Firehose在Facebook的Scribe顶端实现,让消息传输可以异步实现。

下图展示了该架构:

简析Instgram的搜索架构

自系统化之后,Thrift中跨请求对象再次复用;同时无需自定义反序列化,消费者便可直接消费所传递的信息。Slipstream架构中与照片对应的子集如下所示:

struct User { 1: required i64 id; 2: string username; 3: string fullname; 4: bool is_private; ... } struct Media { 1: required i64 id;  2: required i64 owner_id; 3: required MediaContentType content_type; ... } struct LikeEvent { 1: required i64 liker_id; 2: required i64 media_id; 3: required i64 media_owner_id; 4: Media media; 5: User liker; 6: User media_owner; ... 8: bool is_following_media_owner; } union InstagramEvent { ... 2: LikeEvent like; ... } struct FirehoseEvent { 1: required i64 server_time_millis; 2: required InstagramEvent event;     }

Firehose频道的信息作为best-effort delivery,在消息传递中预计只有很小比例的数据丢失。在搜索时,我们通过数据核对进程或base build建立起最终一致性:每天晚上都会对Instagram连接到Hive的所有PostgreSQL数据库进行截图存档,并定期在这些Hive表格与结构中查询每个垂直搜索的所有文档;将base build与从Slipstream中获取的数据相合并,以确保在数据丢失的情况下,系统也保持最终一致性。

数据输出 处理查询

如果数据正确接收,则搜索架构可在一定的约束下高效提取相关的文档,我们称之为“约束查询(constraint a query)”,一般是根据用户提供的文字(例如:用户输入“Justin”,实际想搜索Justin Bieber)所衍生。在Unicorn中,查询被重写为明确表达目的的 S-Expressions ,比如:

(and user:maxime (apply followed_by: followed_by:me)     )

以上代码翻译过来就是:查找我关注、名叫maxime的人所关注的人。在搜索架构中,这个过程分两步处理:

  • 生成候选集:找出一组与给定查询匹配的文档,Instagram的服务器后端使用反向索引(reverse index)结构,即通过关键词索引找到多组文档。举例来说,输入关键词“name:justin”就会出现包含“justin”的用户名集合。
  • 排序:从所有候选集中选出最佳文档。获取候选文档后,从文档的元数据编码中找出特征,例如:用户Justin Bieber的特征之一是关注者多达3.23千万。系统会将这些特征用于计算“拟合度值(goodness)”,以便对候选子集进行排序。拟合度可通过机器学习或手动调整而生成——在机器学习案例中,针对特定候选者,我们可以设计点击或关注有所差异的特征。

通过这两个步骤,最终得出指定查询的最佳文档有序列表。

社交图谱搜索

在优化搜索功能时,为了提供更具个性化的搜索结果,Instagram现在会将用户关注的人以及他们所关注的人都纳入搜索范围。这样一来,基于用户所关注的人再来查找某人会更容易。

使用Unicorn后,我们能够对Instagram上的所有帐号、媒体、标签和地址,还有其间各类关系生成索引。举例来说,通过对某个用户的关注者编辑索引,Unicorn可以回答这类问题:

“用户X与用户Y同时关注的账号有哪些?”

同样的,通过对媒体中的位置进行索引,Unicorn能得出如下信息:

“我关注的帐号所发布的媒体是在纽约拍摄的”。

[b]优化帐号搜索功能[/b]

单独使用Instagram的图谱的话体验不佳,不足以找到想要查找的帐号,必须结合Unicorn的搜索排序架构使用才能奏效。

完成这一目标的方法之一是在Instagram上为现有连接建立模型。在Facebook上,账号间的基本关系是非定向的(通常会互加好友),而在Instagram上却不一定要回粉。我们的团队必须对搜索排序算法进行修改,以存储并检索Instagram关注图谱中的帐号信息。对Instagram来说,要使用Unicorn按照混合的方式来检索帐号:“你关注的人所关注的人”和“关注你的人所关注的其他人”。

此外,Instagram的用户关注彼此的原因各种各样,某位用户无需与他所关注的用户保持完全一致的兴趣点。我们的团队构建了一个模型,针对每个用户所关注的帐号进行排序,因此在搜索时,与搜索者关系更为密切的用户所关注的对象会优先显示。

统一搜索框

简析Instgram的搜索架构

有时,搜索查询的最佳匹配可能是标签或地点。根据之前的经验,Instagram的用户必须明确选择是搜索帐号还是搜索标签。之前搜索标签或地点时,必须要在不同类型的结果中进行选择,而现在有了更简单的替代方案——我们建立了一个排序框架,能够预测正在搜索的用户希望查到的结果类型。在测试时,我们发现将帐号与标签融合可将标签的点击率提升20%以上,同时并未对帐号搜索性能有太大影响。

在用户使用Instagram时,我们的分类器也对搜索日志进行了个性化,并启用了机器学习功能。查询日志按照国家来汇总,以确定针对给定搜索词(如“#tbt”)的搜索更有可能是标签搜索还是帐号搜索,再结合其他信息,比如给定用户过去的搜索记录,以及可展示的搜索结果质量,创建出搜索结果的最终混合列表。

媒体搜索

Instagram的搜索架构常用来加强与用户输入差距较大的搜索,而Instagram最大的垂直搜索便是媒体搜索,它包含了数以亿计的日志,每个都收获数万亿的点赞。与其他层面不同,媒体搜索是纯粹的基础架构,用户从不在应用上输入明确对媒体的搜索,我们使用它来加强其它显示媒体的功能,如:浏览、标签、地点以及最新推出的编辑集群(editorial cluster)。

简析Instgram的搜索架构

候选集生成

由于没有明确的查询需求,我们在媒体反向索引关键词上发挥了创造力,对关键字做了不同的切分。下面的表格列出了目前媒体索引所支持的一些索引词类型:

简析Instgram的搜索架构

在各个日志列表中,媒体按照时间逆序排列(静态排名),将更近的搜索结果显示在最上面。举个例子,通过单一查询(term owner: 181861901),我们便能查找到 @thomas 的个人主页。扩展到标签上,搜索(term 标签: #hyperlapse),我们就能找到带有#hyperlapse标签的最新媒体。Unicorn还允许用户发送(标签:#hyperlapse,owner:181861901)找到用户@thomas所发布的、带有#Hyperlapses标签的日志。

许多索引词的存在就是为了鼓励搜索结果多样化,比如,我们可能对此感兴趣:确保一些带有#hyperlapse标签的候选日志是来自认证账号的。那么通过Unicorn的WEAK AND运算符,可以确保至少有30%的候选日志来自认证账号:

wand  (term hashtag:#hyperlapse) (term verified:1 :optional-weight 0.3)     )

我们探索多样性,以便在标签与位置的“顶端”部分提供更符合的内容。

功能

尽管日志是按照时间顺序来排列的,我们一般想要的是指定查询(标签、位置等)的热门媒体。在生成候选集之后,我们会执行排名进程,通过对每份文档进行评分来选出最佳媒体。评分功能包含一系列功能,最终输出的分数代表与查询指定文档拟合度最高的结果。

  • 视觉: 查看图片本身可视内容的功能。具体来讲,在尝试对图片内容分类时,Instagram会使用深层神经网络(DNN)图像分类器,然后采用人脸识别技术来确定图片中人脸的数目与尺寸大小。
  • 日志元数据: 查看指定日志非视觉内容的功能。Instagram的许多日志都包含标题、地理位置标记、标签以及/或者提示信息,有助于确认搜索的相关性。比如FEATURE_IG_MEDIA_IS_LOCATION_TAGGED就是确定某个日志是否包含地理位置标记的标识功能。
  • 发布者: 查看特定日志发布者的功能。某个日志的一些最为丰富的信息都是由发布者确定的,比如通过FEATURE_IG_MEDIA_AUTHOR_VERIFIED就可以鉴定该日志的发布者是否是认证用户。

我们索引中的功能可以被大致分为三类,根据使用情况不同,其权重也不尽相同。在位置页面的“顶端”部分,我们可能想要分辨这些图片是该地理位置的照片,还是其附近的照片,并将包含大量面孔的照片排在后面。Instagram还使用per-query-type排序模型,针对特定的应用页面对合适的选择进行建模。

案例研究:发现

Instagram的媒体搜索架构还拓展出了发现功能,为那些没有明确搜索目标的用户推送有趣的内容。Instagram的浏览日志功能可以通过社交图谱,为用户推送附近的人感兴趣的内容。具体来说,发现的来源就是“你点赞的图片的作者,他所喜欢的照片”,我们可以在单个unicorn查询中将此功能编码:

(apply liker:(extract owner: liker:<userid>))

这就是一个由内及外的过程:

  • liker::你曾点赞的日志
  • (extract owner:…):这些日志的发布者
  • (apply liker:..):他们点赞的媒体

这一查询的候选结果生成之后,我们就能利用现有的排序架构为用户推送热门日志。与带有标签及地理位置标记的热门日志不同,发现功能的评分函数是通过机器学习演化的,而不是人工手动调整的。

简析Instgram的搜索架构

原文  http://www.iteye.com/news/31576
正文到此结束
Loading...