我试图使用Postgres的pg_similarity扩展计算Django应用程序中长整数对(每个20位)的汉明距离,并且很难弄清楚如何执行此操作。 Django似乎没有当前的BitString字段(这是理想的,但django_postgres似乎已经不存在了),所以我试图将整数转换为SQL查询本身的位串。我目前的查询:
sql = ''' SELECT id, hamming(
"HashString"::BIT(255),
%s::BIT(255)
) as hamming_distance
FROM images
HAVING hamming_distance < %s
ORDER BY hamming_distance;'''
正在抛出数据库错误:cannot cast type numeric to bit
。我究竟做错了什么?我还能尝试什么?
答案 0 :(得分:3)
Per the manual,如果你的“长整数”实际上是一个“长整数”,即bigint / int8,那么转换是正确的方法:
regress=> SELECT ('1324'::bigint)::bit(64);
bit
------------------------------------------------------------------
0000000000000000000000000000000000000000000000000000010100101100
(1 row)
但是(编辑)你实际上是在询问如何将整数numeric
转换为bit
。不那么简单,坚持下去。
你也不能将数字移位,所以你不能轻易将其移位到64位块,转换和重组。
你必须使用除法和模数。
假设:
SELECT '1792913810350008736973055638379610855835'::numeric(40,0);
你可以在'bigint'块中得到它,当乘以max-long(9223372036854775807)时,它们的位置值会产生原始值。
e.g。这得到最低的64位:
SELECT ('1792913810350008736973055638379610855835'::numeric(40,0) / '9223372036854775807'::numeric(256,0)) % '9223372036854775807'::numeric(40,0);
这将获得最多256位数及其指数的给定值的所有块
WITH numval(v) AS (VALUES ('1792913810350008736973055638379610855835'::numeric(40,0)))
SELECT exponent, floor(v / ('9223372036854775807'::numeric(256,0) ^ exponent) % '9223372036854775807'::numeric(40,0)) from numval, generate_series(1,3) exponent;
您可以将其重新组合为原始值:
WITH
numval(v) AS (
VALUES ('1792913810350008736973055638379610855835'::numeric(40,0))
),
chunks (exponent, chunk) AS (
SELECT exponent, floor(v / ('9223372036854775807'::numeric(40,0) ^ exponent) % '9223372036854775807'::numeric(40,0))::bigint from numval, generate_series(1,3) exponent
)
SELECT floor(sum(chunk::numeric(40,0) * ('9223372036854775807'::numeric(40,0) ^ exponent))) FROM chunks;
所以我们知道它已经正确分解了。
现在我们正在使用一系列64位整数,我们可以将每个整数转换为位域。因为我们使用有符号整数,所以每个只有63个有效位,所以:
WITH
numval(v) AS (
VALUES ('1792913810350008736973055638379610855835'::numeric(40,0))
),
chunks (exponent, chunk) AS (
SELECT exponent, floor(v / ('9223372036854775807'::numeric(40,0) ^ exponent) % '9223372036854775807'::numeric(40,0))::bigint from numval, generate_series(1,3) exponent
)
SELECT
exponent,
chunk::bit(63)
FROM chunks;
给出了每个63位块的位值。然后我们可以重新组装它们。没有位域连接运算符,但我们可以移位bit_or
,然后将其包装到SQL函数中,产生怪异:
CREATE OR REPLACE FUNCTION numericint40_to_bit189(numeric(40,0)) RETURNS bit(189)
LANGUAGE sql
AS
$$
WITH
chunks (exponent, chunk) AS (
SELECT exponent, floor($1 / ('9223372036854775807'::numeric(40,0) ^ exponent) % '9223372036854775807'::numeric(40,0))::bigint
FROM generate_series(1,3) exponent
)
SELECT
bit_or(chunk::bit(189) << (63*(exponent-1)))
FROM chunks;
$$;
可以在这里看到:
regress=> SELECT numericint40_to_bit189('1792913810350008736973055638379610855835');
numericint40_to_bit189
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010101000100110101101010001110110110101001111100011100011110000010110
(1 row)
答案 1 :(得分:2)
感谢最初的答案Craig Ringer!这是函数的正确版本。它最多支持300位,如果需要可以扩展。
CREATE OR REPLACE FUNCTION numeric_to_bit(NUMERIC)
RETURNS BIT VARYING AS $$
DECLARE
num ALIAS FOR $1;
-- 1 + largest positive BIGINT --
max_bigint NUMERIC := '9223372036854775808' :: NUMERIC(19, 0);
result BIT VARYING;
BEGIN
WITH
chunks (exponent, chunk) AS (
SELECT
exponent,
floor((num / (max_bigint ^ exponent) :: NUMERIC(300, 20)) % max_bigint) :: BIGINT
FROM generate_series(0, 5) exponent
)
SELECT bit_or(chunk :: BIT(300) :: BIT VARYING << (63 * (exponent))) :: BIT VARYING
FROM chunks INTO result;
RETURN result;
END;
$$ LANGUAGE plpgsql;
答案 2 :(得分:0)
尝试使用python:
sql = sorted(([hamming("HashString", %s,image.id) for image in Image.objects.all() if hamming("HashString",%s) < %s])