Sphinx Mulit-Level 随机排序

Sphinx Mulit-Level Sort with Randomize

这是我对 Sphinx Sort 的挑战,我有供应商支付溢价安置和那些不支付的供应商:

我已经下了一个 multi-level 订单,其中包括 PaidVendorStatus,它是 0 或 1,如:

order by PaidVendorStatus,Weight()

所以本质上我最终得到了多个排序组​​:

问题是我有三个目标:

  1. 在任何给定的排序组中随机排列每个供应商的优先级
  2. 让每个供应商的 'odds' 被随机分配到最高位置,无论他们在组中返回了多少记录(因此,如果供应商 A 有 50 个结果,供应商 B 有 2 个结果,他们仍然有 50 % 被随机分配给任何给定地点的几率)
  3. 理想情况下,在任何给定搜索中保持相同的结果顺序(这样,如果用户再次搜索,将显示相同的顺序

我尝试过各种解决方案:

Select CRC32(Vendor) as RANDOM...Order by PaidVendorStatus,Weight(),RANDOM

解决了 23 除了由于 CRC32 的性质总是把同一个供应商放在第一位(第二,第三等)所以本质上没有解决根本问题。

我尝试在我的 Sphinx Configuration 中制作一个 sphinx sql_attr_string,这是一个 concatenation 的供应商和记录标题 (Select... concat(Vendor,Title) as RANDOMIZER..)` 然后用它来随机化

Select CRC32(RANDOMIZER) as RANDOM...

这解决了 13,因为现在 Title 字段被抛出在随机化错误中,因此同一供应商并不总是获得第一个账单。但是,它在 2 处失败了,因为本质上我只是按标题排序,因此有两个结果的供应商 B 现在被排在第一位的变化非常小。

在理想的世界里,我自然可以这样点菜;

Order by PaidVendorStatus,Weight(),RAND(Vendor)

但这是不可能的。

对此有任何想法表示赞赏。顺便说一句,我按照 Barry Hunter 的建议 this thread on UDF 检查了一下,但除非我完全不理解(可能),否则它似乎不是解决这个问题的方法。

好吧,一个想法是:

SELECT * FROM (
  SELECT *,uniqueserial(vendor_id) AS sorter FROM index WHERE MATCH(...) 
       ORDER BY PaidVendorStatus DESC ,Weight() DESC LIMIT 1000
) ORDER BY sorter DESC, WEIGHT() DESC:

这利用带有 pysudeo 子查询的 SPhixnes 'multiple sort' 函数。

这很有效,因为内部查询首先按 PaidVendor 排序,因此它们的项目是第一位的。这会影响调用 unqique serial 的 ordr。

这并不是真正的 'randomising' 结果,似乎您只是随机化它们以混淆供应商(因此单个供应商不会支配结果。Uniqueserial 由 'spreading' 特定供应商提供结果- 结果将倾向于在供应商之间循环。

这很棘手,因为它利用了一个相对未记录的 sphinx 功能 - 子查询。

有关 UDF,请参阅 http://svn.geograph.org.uk/svn/modules/trunk/sphinx/

仍然没有您的偏向随机答案(如 2.)

但我想起了另一个对 3 有帮助的功能。- 可以为随机数提供特定的种子。通常随机生成器是从当前时间开始播种的,它给出不断变化的值,但使用特定的种子。

然而,种子是一个数字,因此需要一个可预测但不断变化的数字。可以CRC查询吗?

... sphinx 不支持选项中的表达式,因此必须计算应用程序中的哈希值。

<?php

$query = $db->Quote($_GET['q']);
$crc = crc32($query);

$sql = "SELECT id,IDIV(WEIGHT(),100) as i,RAND() as r FROM index WHERE MATCH($query) 
             ORDER BY PaidVendorStatus DESC,i DESC,r ASC OPTION random_seed=$crc";

如果希望结果缓慢演变,请添加当前日期,这样每一天都是一个新的选择...

 $crc = crc32($query.date('Ymd'));