从电子商务网站订购的前k项

时间:2015-01-29 16:25:27

标签: algorithm data-structures

在购物网站中订购top-k商品的最佳方式(算法/数据结构)是什么,相关信息在每个服务器的日志中?  我正在考虑一种方法,该方法涉及维护固定大小k的双向链表,每个节点具有计数变量(可以是范围)一组共享相同计数的产品ID。随着每个事件(productId)的到达,遍历列表并计数更新,并且如果可能的话,提升到下一个更高的计数范围。
  上述方法是否正确?还有哪些其他更好的解决方案?

3 个答案:

答案 0 :(得分:1)

你的方法不正确,你说列表是固定大小的,但这表明你已经知道哪些是前k个元素 - 显然不是这种情况。假设您已经填充了一个大小为k的列表,并且您遍历了一半的项目 - 现在,下一个项目重复整个集合(n / 2次重复) - 它显然应该位于前k,但是你永远不会把它放在你的清单中 - 所以结果是错误的。

您可以通过某些方式解决问题,具体取决于限制(主要是日志文件的大小)。

方法1:构建直方图并找到前k个元素

首先,迭代列表,并构建一个histogram(基于哈希/树的地图map<item,int>) - 然后,在找到每个元素重新出现的数字后,它只是找到前k个元素, this thread详细介绍了该问题。
通过维护一个最小堆,迭代你的集合,为每个项找到顶部k - 检查它是否高于堆中的最小项,如果是,则从堆中弹出元素并插入此项代替。

建立直方图只需:

histogram = new map<item,int>
for each element x in the list:
  val = (x is a key in map? map.get(x) : 0) + 1
  map.put(x,val)

如果使用基于树的地图,此方法的复杂性为O(nlogn),如果使用基于散列的地图,则为O(nlogk)。这非常有效,但如果您的日志文件包含数万亿条目,则可能无法在一台计算机上合理的时间内完成,并且您需要在多台计算机上分配您的工作。这引导我们采用下一个方法。

方法2: map-reduce

此方法适用于非常大的日志文件,可通过在大型群集上分发问题来完成。这是一种更复杂的方法 - 但对于非常大的文件,使用一台机器可能无法找到前k个元素。

map(file):
  for each item in file:
      emit(item,1)
reduce(item,list)
  sum = 0
  for each x in list:
      sum = sum + x
  emit(item,sum)

在这个阶段你处理了列表并构建了一个直方图,现在我们需要找到前面的k,想法是分割数据,这样每台机器都会获得一部分,并产生它的本地顶部K元素,然后将所有#machines * K元素发送到将选择全局前k

的单个“主”机器

答案 1 :(得分:0)

除了Amit的回答,还有概率数据结构来处理这种查询。它们可能牺牲精度以减少资源使用。

以下是关于此的论文的链接:

Efficient Computation of Frequent and Top-k Elements in Data Streams

指向实现的链接(使用Java)。

https://github.com/addthis/stream-lib/blob/master/src/main/java/com/clearspring/analytics/stream/StreamSummary.java

答案 2 :(得分:0)

根据您的提交,我想添加一个建议。如果P是产品数量,我认为

  • nkP
  • 小很多
  • 你有一些受欢迎的产品和许多低频产品(重尾) - 这通常适用于许多自然数据集。
  • 您无法访问map-reduce(在这种情况下,Amit&#39的解决方案2最简单)

如果是这种情况,那么您的解决方案可能是

  1. 在每台服务器上单独构建直方图和top-k列表(如Amit所述)。
  2. x成为第k个最常见产品的本地计数。
  3. 将直方图中带有本地计数lc >= x/n的所有元素发送到中央服务器。
  4. 合并它们并找到临时的全球顶级k元素。
  5. y计算临时第k个全球最常见的产品
  6. 对于全球频率为f >= y/n的所有产品,请求所有服务器将其本地频率发送到中央服务器。
  7. 合并所有元素并找到前k。
  8. 您按y/nx/n进行过滤的原因是任何产品必须至少有一个服务器lc >= gc/nxy是我们想要找到的频率最低的产品的全局数量的下限。

    这种方法的网络流量将比map-reduce模型少得多 - 但是编程也需要更长

    如果您计划进行更多日志分析,我肯定会建议您查看Hadoop(和Hive / Spark/SparkSQL)或Google BigQuery。设置需要一段时间,但投资将很快在节省的编程时间内自行支付。