- nebula 版本:3.0.1
- 部署方式:单机,windows
- 安装方式:Docker
- 是否为线上版本:Y
- 硬件信息
- 磁盘:SSD
- CPU、内存信息:4核,16G
- 问题的具体描述
你好,请教一下,VID使用的字符串类型。
我的数据中个别记录的主键特别长,但绝大多数记录的主键都很短,想使用hash 编码的方式生成。
python中如何调用和nebula相同的hash算法。
现在确实没有现成的 mmh2 64 位的 python 包
只能找到 mmh3 和 mmh2 32 bit 的
mmh3 和 mmh2 32 bit 是否可以实现生成的hash值和nebula的相同?或者对于个别主键特别长的问题有其他解决方法?
- yield hash(xxx) 要求远端算一下
- 参考种子自己实现下,和 yield hash(xxx)对比
python的随机种子是10进制int类型的,“0xc70f6907UL”代表的是什么类型的数据?是不是可以转成10进制int类型?
Python 里16进制数字表示和 c 是一样的,你可以直接用它。
$ python
Python 3.8.10 (default, Mar 15 2022, 12:22:08)
>>> 0xc70f6907
3339675911
Python 里现成的库不支持 mmh2 64 bit,所以不能和 nebula 服务端一致。
不过如吴老师提到,如果允许你可以从 nebulaclient 直接 return hash(“foo”) 请求 nebula 的 hash。
如果量大的话,可以考虑自己去实现这个 hash。
- 比如这个 GitHub - messense/murmurhash2-py: murmurhash2 for Python 是用 python 去调 rust 写的 mmh2 32bit 的库,可以试着改成 64 bit 的。
- https://stackoverflow.com/questions/13305290/is-there-a-pure-python-implementation-of-murmurhash 这里有纯python 的实现,不过我试了一下不行,估计也不是 mmh2 64 bit,也许更好改,不过量大的话应该性能没有 rust 的快。
- 这个是 mmh3 64 bit 的 python 库,底下是 cpp 的,GitHub - hajimes/mmh3: Python wrapper for MurmurHash (MurmurHash3), a set of fast and robust hash functions.
后边我有时间可以研究做一个出来,不过短期有点忙。
好的 我试一下 十分感谢
搞出来了一个能用的
def bytes_to_long(bytes):
assert len(bytes) == 8
return sum((b << (k * 8) for k, b in enumerate(bytes)))
def murmur64(data, seed = 0xc70f6907):
import ctypes
m = ctypes.c_uint64(0xc6a4a7935bd1e995).value
r = ctypes.c_uint32(47).value
MASK = ctypes.c_uint64(2 ** 64 - 1).value
data_as_bytes = bytearray(data)
seed = ctypes.c_uint64(seed).value
h = seed ^ ((m * len(data_as_bytes)) & MASK)
off = int(len(data_as_bytes)/8)*8
for ll in range(0, off, 8):
k = bytes_to_long(data_as_bytes[ll:ll + 8])
k = (k * m) & MASK
k = k ^ ((k >> r) & MASK)
k = (k * m) & MASK
h = (h ^ k)
h = (h * m) & MASK
l = len(data_as_bytes) & 7
if l >= 7:
h = (h ^ (data_as_bytes[off+6] << 48))
if l >= 6:
h = (h ^ (data_as_bytes[off+5] << 40))
if l >= 5:
h = (h ^ (data_as_bytes[off+4] << 32))
if l >= 4:
h = (h ^ (data_as_bytes[off+3] << 24))
if l >= 3:
h = (h ^ (data_as_bytes[off+2] << 16))
if l >= 2:
h = (h ^ (data_as_bytes[off+1] << 8))
if l >= 1:
h = (h ^ data_as_bytes[off])
h = (h * m) & MASK
h = h ^ ((h >> r) & MASK)
h = (h * m) & MASK
h = h ^ ((h >> r) & MASK)
return ctypes.c_long(h).value
$ python
>>> print(str(murmur64(bytes("to_be_hashed", encoding = "utf8"), seed=0xc70f6907)))
-1098333533029391540
(root@nebula) [(none)]> YIELD hash("to_be_hashed");
+----------------------+
| hash("to_be_hashed") |
+----------------------+
| -1098333533029391540 |
+----------------------+
Got 1 rows (time spent 550/6257 us)
Ref: hash - Is there a pure python implementation of MurmurHash? - Stack Overflow
放在了 gist 上
https://gist.github.com/wey-gu/5543c33987c0a5e8f7474b9b80cd36aa
谢谢
追求性能还是用 rust/cpp 打包成 python module
是 python3么?
是的,3.7,和3.8都试了一下。
你在windows下装的python是64 bit 的么?
是的,我试过了在linux上是没问题的,应该是跟系统有关
嗯嗯,还不是位数的问题,有意思,好奇是哪一步结果有差别,我没有环境,如果你感兴趣可以两边每一步print一下看看是哪里行为有差异
改一个方法就行了, ctypes.c_longlong(h)
return ctypes.c_longlong(h).value
啊哈,原来 c 里边win和unix的 long 的定义不同,cool
此话题已在最后回复的 7 天后被自动关闭。不再允许新回复。