目录

算法ID的设计

概述

推荐系统一般除了会返回推荐的结果 id 列表以外,还会返回一些辅助参数,例如算法 id,也可以称为推荐的 rdna(recommended dna),可以用于描述该推荐结果的「来龙去脉」。比如说,推荐流程经过了召回、混排和排序三个阶段,而每个阶段都可能会有 ab 实验,为了标识所属阶段和实验,都会给实验分配一个 id,用于追踪推荐的完整过程。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
  "status": true,
  "result": [
    {
      "rdna": 1150982,
      "itemId": "69",
      "itemType": "Item",
      "debug": {
        "rtime": 1544502577084
      }
    },
    {
      "rdna": 1150982,
      "itemId": "0",
      "itemType": "Item",
      "debug": {
        "rtime": 1544502577084
      }
    },
    {
      "rdna": 1150982,
      "itemId": "88",
      "itemType": "Item",
      "debug": {
        "rtime": 1544502577084
      }
    }
  ]
}

传入相应的三个参数,可以返回一个 Long 类型的 rdna 值,而在分析过程中,也可以通过返回值的 rdna 解析出 recallId,mixId 和 rerankId,以此来区分业务。rdna 的实现其实很简单,主要运用了位运算。也可以用 python 或者其他语言来实现。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 该样例类的参数为召回 id混排 id  重排 id并且都是在0到1023间的整数
case class DNA(recallId: Int, mixId: Int, rerankId: Int) {
 require(recallId < 1024, s"Invalid recall id: [ $recallId ] > 1024 or < 0.")
 require(mixId < 1024, s"Invalid mix id: [ $mixId ] > 1024 or < 0.")
 require(rerankId < 1024, s"Invalid rerank id: [ $rerankId ] > 1024 or < 0.")

def dnaToLong: Long = {
 recallId.toLong + (mixId << 10).toLong + (rerankId << 20).toLong
 }
}

# 该对象通过传入一个 dna 数值分别取得召回 id混排 id  重排 id
object DNA {
 def apply(dnaCode: Long): DNA = {
 val rc = dnaCode & 1023
 val m = dnaCode >> 10 & 1023
 val rr = dnaCode >> 20 & 1023
 new DNA(rc.toInt, m.toInt, rr.toInt)
 }
}

算法ID如何转rdna

考虑一个召回,混排,精排的组合为(6, 0, 7),如何转换成为 rdna。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 首先计算 recallId
recallId.toLong = 6

# 然后计算 mixId
(mixId << 10).toLong = 0

# 最后计算 rerankId
(rerankId << 20).toLong = 7340032

# 最后的 rdna 是通过将以上三部分的结果相加得到的
rdna = 6 + 0 + 7340032 = 7340038

rnda如何转算法id

根据 rdna 获得召回,混排,精排的组合。仍然使用实例1的数据:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 以下是解析 rdna 为7340038的过程
# 十进制化为二进制
7340038 => 100 0110 0000 0000 0000 0000 1000

recallId = dnaCode & 1023
= 7340038 & 1023
= 100 0110 0000 0000 0000 0000 1000 & 11 1111 1111
= 6

mixId = dnaCode >> 10 & 1023
= 7340038 >> 10 & 1023
= 7168 & 1023
= 0

rerankId = dnaCode >> 20 & 1023
= 7340038 >> 20 & 1023
= 7 & 1023
= 7

解析点击、行为日志的时候,可以通过注册 Hive 的 UDF 函数来解析不同的推荐业务的 rdna,从而实现报表的开发。

脚本解析

提供一个样例脚本,用于在 shell 模式下方便解析,其实就是一个关于位运算的 shell 脚本。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/bin/bash

function longtordna() {
  RECALL=$1
  MIX=$2
  RERANK=$3
  RDNA=$((RECALL + (MIX << 10) + (RERANK << 20)))
  echo "Input racall: $RECALL, mix: $MIX and rerank $RERANK, convert to rdna: $RDNA."
}

function rdnatolong() {
  RDNA=$1
  echo "Input rdna: $RDNA to convert to recall: $((RDNA & 1023)), mix: $((RDNA >> 10 & 1023)) and rerank: $((RDNA >> 20 & 1023))."
}

function usage() {
cat << EOF
  Usage: ./rdna.sh longtordna  recallId  mixId  rerankId
         ./rdna.sh rdnatolong rdna
         ./rdna.sh help
EOF
}

case "$1:$2:$3" in
    longtordna:*)
        longtordna "${@:2}"
        ;;
    rdnatolong:*)
        rdnatolong $2
        ;;
    h|help)
        usage
        ;;
    *)
        usage
        exit 0
esac

总结

实际上 rdna 的设计、叫法这些都不重要,重要的是理解一种思想,就是通过你的推荐系统推荐出来的东西,可以通过一定的工具,来排查推荐的来龙去脉,这在实际的业务运营上是很重要的,假设有天用户反馈推荐的内容并不感兴趣,通过这些工具,我们可以清晰的找到推荐的逻辑,这样可以为以后的优化提供非常重要的依据,至于怎么做,或者是否做成可视化、血缘关系之类的,就看开发的能力和时间了。

警告
本文最后更新于 2017年5月9日,文中内容可能已过时,请谨慎参考。