rmu*_*ler 5 postgresql hamming-distance
我们正在将 MySQL 5.7 数据库迁移到 PostgreSQL 9.6。
一个真正的问题是bit_countPostgreSQL缺乏功能。此功能在即将发布的版本 10 中也不可用。
当前 MySQL 代码片段(简化):
-- mysql specific, tested with 5.7.19
select code,phash,bit_count(phash ^ -9187530158960050433) as hd
from documents
where phash is not null and bit_count(phash ^ -9187530158960050433) < 7
order by hd;
Run Code Online (Sandbox Code Playgroud)
我们尝试了一个简单的解决方案(将 BIGINT 转换为字符串并计算“1”),但与 MySQL 相比,它的表现非常糟糕。
Java使用了 Hacker's Delight 的一个技巧,但 AFAIK 这在 PostgreSQL 中是不可能的,因为该>>>运算符(也)不可用。
问题:是否有与 MySQL 性能相当的解决方案/解决方法?
更新 1
我能找到的最佳解决方案是基于这个 SO 答案:
首先创建bit_count函数:
CREATE OR REPLACE FUNCTION bit_count(value bigint)
RETURNS numeric
AS $$ SELECT SUM((value >> bit) & 1) FROM generate_series(0, 63) bit $$
LANGUAGE SQL IMMUTABLE STRICT;
Run Code Online (Sandbox Code Playgroud)
现在我们可以使用与 MySQL 几乎相同的 SQL:
-- postgresql specific, tested with 9.6.5
select code,phash,bit_count(phash # -9187530158960050433) as hd
from documents
where phash is not null and bit_count(phash # -9187530158960050433) < 7
order by hd;
Run Code Online (Sandbox Code Playgroud)
更新 2
基于@a_horse_with_no_name 评论,我尝试了这个功能:
-- fastest implementation so far. 10 - 11 x faster than the naive solution (see UPDATE 1)
CREATE OR REPLACE FUNCTION bit_count(value bigint)
RETURNS integer
AS $$ SELECT length(replace(value::bit(64)::text,'0','')); $$
LANGUAGE SQL IMMUTABLE STRICT;
Run Code Online (Sandbox Code Playgroud)
然而,这仍然比 MySQL 慢 5 - 6 倍(在相同硬件上用完全相同的 200k phash 值的相同数据集进行测试)。
函数 bit_count 从 PostgreSQL 版本 14 开始可用,请参阅 位字符串函数和运算符。
例子:
select bit_count(B'1101');
Run Code Online (Sandbox Code Playgroud)
结果是 3。
请注意,该函数是针对位类型和位变化类型定义的。因此,如果您想将其与整数值一起使用,则需要进行强制转换。
例子:
select cast (cast (1101 as text) as bit varying);
Run Code Online (Sandbox Code Playgroud)
结果是 B'1101'。
结合两个例子:
select bit_count(cast (cast (1101 as text) as bit varying));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2240 次 |
| 最近记录: |