我开始深入研究图形数据库,但我不知道这些图形是如何在内部存储的。假设我有这张图(取自Wikipedia):
如何将此图表序列化为键值对象?(例如Python词典)
我想象两个dicts,一个用于顶点,一个用于边缘:
{'vertices':
{'1': {'Name': 'Alice', 'Age': 18},
'2': {'Name': 'Bob', 'Age': 22},
'3': {'Type': 'Group', 'Name': 'Chess'}},
'edges':
{'100': {'Label': 'knows', 'Since': '2001/10/03'},
'101': {'Label': 'knows', 'Since': '2001/10/04'},
'102': {'Label': 'is_member', 'Since': '2005/7/01'},
'103': {'Label': 'Members'},
'104': {'Label': 'Members'},
'105': {'Label': 'is_member', 'Since': '2011/02/14'}},
'connections': [['1', '2', '100'], ['2', '1', '101'],
['1', '3', '102'], ['3', '1', '103'],
['3', '2', '104'], ['2', '3', '105']]}
但我不确定,这是否是最实用的实施方案。也许“连接”应该在“顶点”字典内。那么,使用键值对象实现图数据存储的最佳方法是什么?我可以在哪里以及在哪里阅读更多相关信息?
可能相关但不重复:How to represent a strange graph in some data structure
答案 0 :(得分:11)
正常模式是没有单独的connections
结构,而是将该信息放在edges
结构中。这给出了类似的东西:
{
'vertices': {
'1': {'Name': 'Alice', 'Age': 18},
'2': {'Name': 'Bob', 'Age': 22},
'3': {'Type': 'Group', 'Name': 'Chess'} },
'edges': [
{'from': '1', 'to': '2', 'Label': 'knows', 'Since': '2001/10/03'},
{'from': '2', 'to': '1', 'Label': 'knows', 'Since': '2001/10/04'},
{'from': '1', 'to': '3', 'Label': 'is_member', 'Since': '2005/7/01'},
{'from': '3', 'to': '1', 'Label': 'Members'},
{'from': '3', 'to': '2', 'Label': 'Members'},
{'from': '2', 'to': '3', 'Label': 'is_member', 'Since': '2011/02/14'} ] }
答案 1 :(得分:5)
似乎没问题 - 每个对象都有它,没有重复。它对“阅读和处理目的”有好处。但没有'最佳'代表。它总是取决于你的目的。你想要能够通过名称快速找到顶点吗?或按日期划分边缘?或者你想快速测试两个顶点是否连接?或者相反 - 您想快速修改图表的某些部分?每个目的都需要不同的数据库表数据结构
答案 2 :(得分:4)
这些图如何在内部存储
如何将此图序列化为键值对象
这些问题不同,需要不同的答案。
在前一种情况下,主要要求可能是有效执行复杂的查询。
我建议研究现有的工业强度解决方案。
用NoSQL术语来说,这些嵌套的键值对象是文档。因此,人们可以研究图如何存储在“分层”多模型数据库中,这些数据库是:
此类数据库的示例是ArangoDB,OrientDB,Azure CosmosDB。
您还可以将“文档数据模型”替换为“宽列数据模型”,因为可以将宽列数据模型视为二维键值模型。
此类数据库的示例是DataStax Enterprise Graph或Grakn。
例如,在ArangoDB中,边stored作为常规文档,但是在特殊集合中。
很显然,所使用的数据结构可能会附带其他索引等(or not)。
那么,使用键值对象实现图形数据存储的最佳方法是什么?
我在哪里以及在哪里可以了解到更多信息?
我建议另一篇来自ArangoDB的文章:
答案 3 :(得分:1)
我不会对Eamonn的答案进行任何更改。
每个顶点和边缘都有3个元素。.id,标签和属性
{
'vertices': {
'1': {'Label' : Person, 'Properties' : { 'Name': 'Alice', 'Age': 18}},
'2': {'Label' : Person, 'Properties' : {'Name': 'Bob', 'Age': 22}},
'3': {'Label': 'Group', 'Properties' : { 'Name': 'Chess'} },
'edges': [
'4' : {'from': '1', 'to': '2', 'Label': 'knows', 'Properties':{'Since': '2001/10/03' , 'Until' : '2001/10/03'}},
'5' : {'from': '2', 'to': '1', 'Label': 'knows', 'Properties':{'Since': '2001/10/04', 'Until' : '2001/10/05'}}
]
}
通过这种方式,您可以按顶点/边缘及其标签和属性进行查询。
答案 4 :(得分:1)
我会像这样序列化它,除了您应该根据查找的内容选择密钥。我以为您使用的是ID,但也许使用名称会更好。
{
'members': {
'1': {
'id': '1',
'name': 'Alice',
'age': 18,
'groups': {
'3': {
'path': 'groups.3',
'since': '2005-07-01'
}
},
'knows': {
'2': {
'path': 'members.2',
'since': '2001-10-03'
}
}
},
'2': {
'id': '2',
'name': 'Bob',
'age': 22,
'groups': {
'3': {
'path': 'groups.3',
'since': '2011-02-14'
}
},
'knows': {
'1': {
'path': 'members.1',
'since': '2001-10-04'
}
}
}
},
'groups': {
'3': {
'id': '3',
'name': 'Chess',
'members': {
'1': { 'path': 'members.1' },
'2': { 'path': 'members.2' }
}
}
}
}
如果您有一种序列化对图形其他部分的引用的方法,那么可以直接将图形序列化为键-值对,这就是我使用'path'
的目的。如果我将其反序列化为字典,则可以考虑将路径值替换为它们所引用的实际字典。请记住,这可能会导致循环引用,如果将其序列化为json或其他内容,可能会导致问题。
答案 5 :(得分:1)
我也将在结构中添加一个邻接。我的看法就是这样,
{
'vertices': {
'1': {'Name': 'Alice', 'Age': 18},
'2': {'Name': 'Bob', 'Age': 22},
'3': {'Type': 'Group', 'Name': 'Chess'}
},
'edges': {
'100' : {'from': '1', 'to': '2', 'Label': 'knows', 'Since': '2001/10/03'},
'101': {'from': '2', 'to': '1', 'Label': 'knows', 'Since': '2001/10/04'},
....
},
'adjacency': {
'1': ['101', '102'],
...
}
}
这样,我可以轻松地找到哪些顶点与顶点相邻,而无需遍历所有的顶点。