【问题标题】:How to implement FNV-1(a) in SQLite?如何在 SQLite 中实现 FNV-1(a)?
【发布时间】:2020-03-23 15:02:04
【问题描述】:

(从https://softwareengineering.stackexchange.com/questions/406813/how-to-implement-fnv-1a-in-sqlite移出)

我正在尝试修改 SQLite 查询(在 Android 中)以伪随机顺序返回其结果。和this question一样,重复查询的顺序需要稳定(例如由于分页、屏幕旋转等),所以我不能只使用ORDER BY RANDOM()。相反,我想使用一个哈希函数,该函数依赖于几个提供稳定性和足够唯一性的输入值。 (其中一个值是表的唯一 ID 列,它是一组相当接近的整数;另一个值更像是一个会话 ID,也是一个整数,在此查询中保持不变。)

根据this well-researched answer,FNV-1 和 FNV-1a 是简单的哈希函数,冲突少且分布良好。但尽管它们很简单,但 FNV-1 和 FNV-1a 都涉及 XOR 操作,以及循环输入的字节。

在查询的每一行中循环是很尴尬的。可以通过展开循环来伪造它,尤其是在只涉及几个字节的情况下。我可以使用两个字节,结合两个输入值(val1 & 255val2 & 255)的 LSB。

SQLite 不直接支持 XOR。我了解A ^ B 可以实现为(A | B) - (A & B)。但是值的重复,加上循环的展开,开始变得笨拙。我可以只使用+(忽略溢出)而不是异或吗?我不需要非常高质量的随机性。该顺序只需要在小整数范围内让不经意的观察者看起来是随机的。

所以我想知道是否有人已经实施了这样的事情。鉴于widely used this hash function is 的方式,似乎已经有针对这种情况的实现。

这是我实施 FNV-1a 的尝试:

SELECT ..... ORDER BY (((fnvbasis + val1 & 255) * fnvprime) + val2 & 255) * fnvprime % range;

我忽略了这样一个事实,即在 FNV 中,XOR 操作(我已替换为 +)只应该影响哈希值的最低 8 位。我也忽略了任何溢出(我希望这只是意味着我不关心的高位丢失)。

对于fnvbasis,我将使用 16777619,对于 fnvprime,我将使用 2166136261。这些是 32 位输入的指定值,因为我没有看到 16 位输入的指定值。对于range,我将使用一个大于此查询返回的预期行数的素数。

那么这是在 SQLite 查询中近似 FNV-1a 的合理方法吗?有更好的现有实现吗? IE。尽管我破坏了真正的 FNV-1a 的操作,它实际上会产生一个对于普通用户来说看起来非常随机的顺序吗?

【问题讨论】:

  • Android sqlite 绑定是否支持添加用户定义的函数?
  • 显然不是 (stackoverflow.com/a/8283265/423105)。 “为了让它工作,您需要使用 NDK编译 SQLite C 库。”对于我要解决的问题,这在开发过程的复杂性上迈出了一大步。

标签: android sqlite hash bitwise-operators


【解决方案1】:

受到来自the previous attempt at this question before I moved it 的 rwong 和 GrandmasterB 的 cmets 的启发,我决定可以预先计算 FNV-1a 循环的第一次迭代,即基于表的唯一 ID 列的哈希。预计算列 fnv1a_step1 设置为

(fnvbasis ^ (ID & 0xFF)) * fnvprime

因为这个值是在表格的每一行单独预计算的,所以可以由应用程序提供,不需要用SQLite表示;因此使用上面的^ (XOR)。此外,如果 ID 是一个字符串,我们也可以在 Java 或 Kotlin 中从中计算出一个 8 位哈希值。但我们甚至可以使用

(fnvbasis + (RANDOM() & 0xFF)) * fnvprime

(如果在 SQLite 中执行此操作,则返回使用 +)因为该值仅计算一次,因此即使从 RANDOM() 计算也是稳定的。

FNV-1a 循环的第二次迭代可以非常简单地在查询的 ORDER BY 子句中计算,使用当前会话 ID,因此它为每个会话生成不同但稳定的排序:

ORDER BY (fnv1a_step1 + sessionId & 0xFF) * fnvprime % range;

我已经在我的应用程序中实现了这个,它似乎可以满足我的要求。一个会话中的顺序是稳定的,但在每个会话中是不同的。

【讨论】:

    猜你喜欢
    • 2018-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    • 2011-10-02
    相关资源
    最近更新 更多