我将django与neo4j用作数据库。我需要在我的rest api中根据节点ID使用短网址。在neo4j中,有一个didn't recommended在数据库中使用的ID,可在应用程序中使用,还有一种方法对于我的短网址来说使用的uuid太长了。因此,我添加了uid生成器:
def uid_generator():
last_id = db.cypher_query("MATCH (n) RETURN count(*) AS lastId")[0][0][0]
if last_id is None:
last_id = 0
last_id = str(last_id)
hash = sha256()
hash.update(str(time.time()).encode())
return hash.hexdigest()[0:(max(2, len(last_id)))] + str(uuid.uuid4()).replace('-', '')[0:(max(2, len(last_id)))]
我有两个问题,首先我在堆栈溢出中读了this question,但仍然不确定MATCH (n) RETURN count(*) AS lastId
是O(1)
,没有提及!这个答案有参考吗?其次,在ID唯一性和速度上是否有更好的方法?
答案 0 :(得分:1)
首先,应在id属性上施加唯一约束,以确保并行create语句不会创建任何冲突。这需要使用标签,但是如果您打算对这些数据进行认真的处理,则需要此故障保护功能。但是这样,您可以为不同的标签设置滚动ID。 (所有索引标签都会有一个计数表。UNIQUECONSTRAINT还会创建一个索引)
第二,您应该像这样在同一密码中进行生成和创建
MATCH (n:Node) WITH count(*) AS lastId
CREATE (:Node{id:lastId})
这将最小化生成和提交之间的时间,从而减少冲突的机会。 (请记住重试因独特的违规而导致的失败尝试)
我不确定您对哈希的处理方式,只是您做错了。您可以生成一个新的基于时间的UUID(它将不需要任何参数)并按原样使用它,或者您使用可识别的ID。 (通过更改UUID,使保证唯一性的逻辑无效,从而大大增加了碰撞机会)
您也可以将当前索引计数存储在节点上,如here所述。它不能保证是线程安全的,但是只要您具有唯一约束并重试违反约束,就不会有问题。这样可以容忍删除节点。
答案 1 :(得分:0)
您的方法不好,因为它基于数据库中的节点数。
如果创建一个节点(称为A),然后删除一个随机节点,然后创建一个新节点(称为B),会发生什么情况。
A和B将具有相同的ID,这就是为什么您基于时间在代码中添加了哈希值(但我几乎不理解这一行:))。
另一方面,Neo4j的ID可确保您在整个数据库中拥有唯一的ID,但在当时没有。默认情况下,Neo4j回收未使用的ID(删除节点后会释放ID)。
您可以通过更改配置(请参阅文档HERE)来更改此行为:dbms.ids.reuse.types.override=RELATIONSHIP
请注意,使用这种配置,即使删除节点,硬盘上数据库的大小也只能增加。
答案 2 :(得分:-1)
为什么不创建自己的标识符?您可以获得最后一个标识符的最大值(我们将其称为RN作为记录号)。
match(n)返回max(n.RN)作为lastID
max是密码中几个数字函数之一。