乐趣区

关于redis:Redis-实战-10-实现内容搜索定向广告和职位搜索

应用 Redis 进行搜寻 P153

通过改变程序搜寻数据的形式,并应用 Redis 来缩小绝大部分基于单词或者关键字进行的内容搜寻操作的执行工夫。P154

根本搜寻原理 P154

倒排索引 (inverted indexes) 是互联网上绝大部分搜索引擎应用的底层构造,它相似于书本开端的索引。倒排索引从每个被索引的文档外面提取一些单词,并记录蕴含每个单词的文档汇合。P154

示例

假如有三个文档:

  • R = “it is what it is”
  • S = “what is it”
  • T = “it is a banana”

咱们就能失去上面的倒排索引汇合:

  • “a”: {2}
  • “banana”: {2}
  • “is”: {0, 1, 2}
  • “it”: {0, 1, 2}
  • “what”: {0, 1}

检索的条件 “what”, “is” 和 “it” 将对应这个汇合:{0,1} ∩ {0,1,2} ∩ {0,1,2} = {0,1}

能够发现 Redis 的汇合和有序汇合非常适合解决倒排索引。

根本索引操作

从文档外面提取单词的过程通常被成为语法分析 (parsing) 和标记化 (tokenization),这个过程能够产生一系列用于示意文档的标记 (token),有时又被成为单词 (word)。P155

标记化的一个常见的附加步骤就是移除非用词 (stop word)。非用词就是那些在文档中频繁呈现却没有提供相应信息量的单词,对这些单词进行搜寻将返回大量无用的后果。P155

本书中实现方向索引的逻辑非常简单:

  1. 将文档划分为单词,并移除一个字符的单词
  2. 对于每个单词获取或创立对应的汇合,将以后文档的惟一标识放入汇合中

如果须要反对中文等,就不能简略进行英文分词,须要分词器进行解决。第一次接触倒排索引是在 Elasticsearch 中,感兴趣的能够理解 Elasticsearch 中倒排索引的实现以及 IK 中文分词器。

根本搜寻操作

在索引外面查找一个单词是非常容易的,只须要获取单词汇合外面的所有文档即可。依据多个单词查找文档时,就须要依据条件解决对应的汇合,再从最终汇合中获取所有文档。P156

能够应用 Redis 的汇合操作实现对不同条件的解决:

  • SINTER / SINTERSTORE: 找出同时蕴含所有指定单词的文档汇合
  • SUNION / SUNIONSTORE: 找出至多蕴含一个指定单词的文档汇合
  • SDIFF / SDIFFSTORE: 找出蕴含某个单词且蕴含其余某些单词的文档汇合

通过以上三类命令,咱们根本能实现条件大部分的与或非操作。

剖析并执行搜寻

咱们应用的查问语句进行分词后具备以下特色:

  • 以 + 结尾的单词:示意这个单词是前一个单词的同义词,须要取并集
  • 以 – 结尾的单词:示意这个单词不心愿蕴含在文档中,须要取差集
  • 其余一般单词:示意用户须要查问这个单词,须要取交加

即:“connect +connection chat -proxy -proxies” 示意查问的文档须要蕴含 “connect” 或 “connection”,同时也要蕴含 “chat”,并且不能蕴含 “proxy” 和 “proxies”。

理论解决时,先对同义词组别离取并集,而后与须要查问的单词一起取交加,最初与不心愿蕴含的单词取差集,这样所失去的汇合就是用户查问的后果集。

对搜寻后果进行排序和分页 P160

上述搜寻性能以及可能搜寻出用户查问的所有文档惟一标识的汇合,当初咱们将依据这个文档惟一标识汇合以及每个文档的具体信息进行排序分页。

  • 文档惟一标识汇合:存储每个文档的惟一标识,例如:{1, 2, 276}
  • 每个文档的具体信息:数据结构为 HASH, 以 doc_{id} 为键,外部存储对应文档的相干信息,例如:"doc:276": {"id": 276, "created": 1324114412, "updated": 132562777, "title": "Troubleshooting...", ...}

对于这种状况咱们能够应用 Redis 的 SORT 命令对文档惟一标识汇合通过援用每个文档的具体信息进行排序分页。(05. Redis 其余命令简介)

有序索引 P162

下面介绍了应用 Redis 进行搜寻,并通过援用存储在 HASH 外面的数据对搜寻后果进行排序分页。接下来将介绍利用汇合和有序汇合实现基于多个分值的复合排序操作,它能提供比 SORT 命令更高的灵活性。P162

对多个数值字段进行排序 P162

假如咱们目前须要依据文档对更新工夫和得票数进行排序,为此咱们须要用两个有序汇合存储相干信息。这两个有序汇合的成员都是文档惟一标识,成员的分值则别离是文档的更新工夫和得票数。

设通过搜寻后满足搜寻条件的文档惟一标识汇合为 filtered_doc_ids,文档惟一标识及其更新工夫对应的有序汇合为 doc_ids_with_update,文档惟一 标识及其得票数对应的有序汇合为 doc_ids_with_votes。那么能够通过 ZINTERSTORE 命令对这三个汇合求交加,最初得出的满足搜寻条件的文档惟一标识及其排序分值对应的有序汇合,再应用 ZRANGE, ZREVRANGE 进行分页获取即可。P162

示例:ZINTERSTORE filtered_doc_ids_with_sort_score 3 filtered_doc_ids doc_ids_with_update doc_ids_with_votes WEIGHTS 0 {update_weight} {vote_weight}

其中:

  • filtered_doc_ids_with_sort_score 为后果有序汇合
  • filtered_doc_ids 的权重为 0,仅用做筛选后果,不用于排序
  • doc_ids_with_update, doc_ids_with_votes 的权重能够进行设置,为 0 时示意不用于排序;为其余数时,示意对应字段对最终排序分所占的权重,负数相当于该字段须要正序排序,正数相当于该字段须要倒序排序。

所思

这种利用分值的办法很奇妙,根本能够实现多字段排序,然而优先级可能难以掌控,难以做到先依照某一字段排序,再依照另一字段排序的模式。因为每个字段对应的分值的数量级可能差异比拟小,这个时候如果须要有排序字段的优先级,那么可能须要对每个权重进行精美地设计才行。

对非数值字段进行排序 P164

下面介绍了应用有序汇合对多个数值字段进行排序,因为有序汇合的分值只能是浮点数,所以非数值字段不能间接用于排序,须要转换成对应的浮点数。但因为双精度浮点数只有 64 个二进制位,理论能应用 63 个二进制位,所以能示意的字符串并不多,只能应用字符串的前几个字符进行分值预计,有余指定字符数的须要补齐到指定字符数。当然如果字符集放大的话,能够从新进行编码计算,进而能够对更长的字符串进行分值预计。P165

当这个分值特地大的时候,可能会引发最终计算的分值溢出而出错的问题。

广告定向 P166

接下来将介绍应用汇合和有序汇合构建出一个简直残缺的广告服务平台 (ad-serving platform)。P166

对广告进行索引 P167

针对广告的索引操作和针对其余内容的索引操作并没有太大的不同,被索引的的广告通常都领有像地位、年龄和性别这类必须的定向参数,并且往往只会返回单个广告。P167

广告的价格 P167

  • 按展现次数计费 (cost per view):这种广告又称 CPM 广告或按千次计费 (cost per mille),每展现 1000 次就须要收取固定的费用
  • 按点击次数计费 (cost per click):这种广告又称 CPC 广告,依据被点击的次数收取固定费用
  • 按动作执行次数计费 (cost per action):又称按购买次数计费 (cost per acquisition),这种广告又称 CPA 广告,依据用户在广告的目的地网站上执行的动作收取不同的费用

为了尽可能简化广告价格的计算形式,将对所有类型的广告进行转换,使得它们的价格能够基于每千次展现进行计算,产生出一个估算 CPM (estimated CPM, eCPM)。P168

  • CPM 的 eCPM 价格能够间接应用 CPM 价格
  • CPC 的 eCPM 价格能够通过将广告的每次点击价格乘以广告的点击通过率 (click-through rate, CTR),而后再乘以 1000 失去
  • CPA 的 eCPM 价格能够将广告的点击通过率、用户在广告投放者的指标页面上执行动作的概率、被执行动作的价格这三者相乘起来,而后再乘以 1000 失去

将广告插入倒排索引 P169

咱们根本能够复用下面提到的搜寻性能,除了会将广告的关键词插入倒排索引,还会将广告的定向参数(地位、年龄和性别等)插入倒排索引中,并记录广告的类型、根本价格和 eCPM 价格。P169

执行广告定向操作 P170

当零碎收到广告定向申请的时候,它要做的就是在匹配用户定向参数的一系列广告外面,找出 eCPM 最高的那一个广告。同时,程序还会记录页面内容与广告内容的匹配水平,以及不同匹配水平对广告点击通过率的影响等统计数据。通过应用这些统计数据,广告中与页面相匹配的那些内容就会作为附加值被计入 CPC 和 CPA 的 eCPM 价格,使得那些蕴含了匹配内容的广告可能更多地被展现进去。P170

计算附加值
计算附加值就是基于页面内容和广告内容两者之间匹配的单词,计算出应该给广告的 eCPM 价格加上多少增量。每个单词都有一个有序汇合,成员为广告 id,成员的分值为以后单词对这则广告的 eCPM 的附加值。P171

在寻找适合的广告时,咱们首先会过滤出匹配定位地位且至多蕴含一个页面单词的广告,而后通过计算附加值的办法代替搜寻,以便实现每次投放价值最高的广告,并可能依据用户的行为学习。同时因为每个广告匹配的内容不同,最优形式应该是应用加权平均值来计算单词局部的附加值,但限于 Redis 自身的命令,咱们最终采取 (max + min) / 2 的模式计算单词局部的附加值(max 示意所有匹配单词的最大附加值,min 示意所有匹配单词的最小附加值),采纳如下命令即可:ZUNIONSTORE final_score 3 base max min WEIGHTS 1 0.5 0.5

从用户行为中学习 P175

首先须要存储用户的浏览记录,包含三局部:(每 100 次就被动更新一次 eCPM)P175

  • 被定向至给定广告的单词(即:内容中单词和给定广告单词的交加)
  • 给定广告被定向的次数
  • 广告中的某个单词被用于计算附加值的次数

其次须要存储用户的点击和动作记录,用于计算 点击通过率 = 点击量或动作次数 / 广告展现次数。(每次都更新 eCPM)P176

最初就是更新 eCPM,包含两局部:

  • 广告的 eCPM:依据广告的理论价格和以后广告的点击通过率,计算出最新的 eCPM
  • 广告单词的 eCPM 附加值:依据广告的根本价格和每个单词的点击通过率,计算出每个单词最新的 eCPM 附加值
改良计划 P179
  • 随工夫流逝:能够仿照 03. Redis 简略实际 – Web 利用 文章的 RescaleItemViewedNum 函数进行定期升高广告的展现次数和点击次数(或者动作执行次数)
  • 减少计数值:能够思考前一天、前一星期或者其余时间段的点击技术,并基于时间段的长短给予不同的权重
  • 应用第二价格拍卖 (second-price auction) 的形式来决定广告位的费用
  • 给予高价广告肯定曝光量:局部工夫内,获取收益排名前 100 的广告,基于它们的 eCPM 的相对值来筛选广告,而不是筛选 eCPM 最高的广告
  • 优化新广告初始 eCPM:

    • 初期应用同类型广告的均匀点击数据
    • 在同类型广告的均匀点击通过率和以后理论点击通过率之间,构建一种简略的反线性关系 (inverse linear relationship) 或者反 S 关系 (inverse sigmoid relationship),直到广告有足够的展现次数为止
    • 人为进步点击通过率,保障有足够多的流量学习真正 eCPM
  • 思考应用真正的贝叶斯统计、神经网络、关联规则学习、聚类计算或者其余技术来计算附加值
  • 将记录信息的逻辑变为异步(能够利用 09. 实现工作队列、音讯拉取和文件散发 中的工作队列实现),进步响应效率

职位搜寻 P180

接下来将应用汇合和有序汇合实现职位搜寻性能,并依据求职者领有技能来为他们寻找适合的职位。P180

遍历适合的职位 P180

第一反馈必定是间接对每一个求职者搜寻所有的岗位,从而找到求职者适合的岗位。但这种办法效率极低(大部分岗位必定是技能对不上的),而且无奈进行性能扩大。P181

搜寻适合的岗位 P181

应用相似下面提到的附加值模式,每次增加一个岗位时,在对应的技能汇合中增加这个岗位的 id (SADD idx:skill:{skill} {job_id}),再在岗位有序汇合中进行增加,成员为岗位 id,成员的分值为所需的技能数量 (ZADD job_required_skill_count {job_id} {required_skill_count})。搜寻的时候就先对求职者所有技能对应的汇合应用 ZUNIONSTORE 操作计算每个公司匹配的技能数量 (ZUNIONSTORE matched {n} idx:skill:{skill} ... WEIGHTS 1 ...),而后再与岗位有序汇合求交加,并让公司有序汇合的权重为 -1 (ZINTERSTORE result 2 job_required_skill_count matched WEIGHTS -1 1),最初获取分值为 0 的所有岗位即可实现搜寻。P181

所思

书上的这个办法比拟麻烦,其实能够应用文章最开始的无序倒排索引,岗位相当于要搜寻的文档,岗位所需的技能相当于单词。

本文首发于公众号:满赋诸机(点击查看原文)开源在 GitHub:reading-notes/redis-in-action

退出移动版