Janusgraph 难以理解如何从 gremlin 查询中操作数据
Janusgraph troubles to understand how to manipulate data from gremlin query
我正在尝试从图形中重建使用 gremlin 查询检索到的数据。
准确地说,我很难找到一种有效的方法来处理返回的数据。
我使用的 JanusGraph 版本是 0.3.1,它在 Cassandra + ES 上 运行ning,它还配置了 ConfiguredGraphFactory。所以我可以动态创建图表。
我正在使用 gremlin javascript 版本 3.4.2(3.3.3 无法正常工作)
我建立了一个小例子来更好地解释我的意思。
此示例中的图表是在没有模式的情况下创建的。
首先,我将使用以下函数连接到图表:
const gremlin = require('gremlin');
const { Graph } = gremlin.structure;
const { DriverRemoteConnection } = gremlin.driver;
const __ = gremlin.process.statics;
const P = gremlin.process.P;
const GREMLIN_URL = "ws://localhost:8182/gremlin";
const GRAPH_NAME = "graphtest";
let connection;
function getTraversal() {
const graph = new Graph();
connection = new DriverRemoteConnection(GREMLIN_URL, { traversalSource: GRAPH_NAME });
return g = graph.traversal().withRemote(connection);
}
function closeConnection() {
if(connection && connection.close) connection.close();
}
然后我将创建一些顶点和边。
我们将有一个用户、两个机构和两个 'trained' 连接用户和机构的边缘:
async function createVerticesAndEdges() {
const g = getTraversal();
const userV = await g.addV('user').property('name', 'Emily').property('identityId', '1234').next();
console.log('user', userV);
const institutionV = await g.addV('institution').property('name', 'University of California').property('identityId', 'CA83').next();
console.log('institution', institutionV);
const institutionV2 = await g.addV('institution').property('name', 'University of Illinois').property('identityId', 'IL847').next();
console.log('institution2', institutionV2);
const trainedE = await g.addE('trained').property('title', 'MS in Computer Science').property('grade', 'B')
.from_(__.V().has('identityId', '1234')).to(__.V().has('identityId', 'CA83')).next();
console.log('trained', trainedE);
const trainedE2 = await g.addE('trained').property('title', 'Political Science').property('grade', 'A')
.from_(__.V().has('identityId', '1234')).to(__.V().has('identityId', 'IL847')).next();
console.log('trained2', trainedE2);
closeConnection();
}
然后,假设我想检索用户参加的所有培训,我还想知道参加培训的机构的名称。
所以我运行的查询是这样的:
async function getUserTrainings() {
const g = getTraversal();
const result = await g.V()
.hasLabel('user')
.has('identityId', '1234')
.as('u').outE()
.hasLabel('trained')
.inV()
.path()
.unfold()
.where(P.neq('u'))
.toList();
closeConnection();
console.log(result);
}
我得到了这个输出:
[
Edge {
id: { relationId: 'odxqw-3b4-27th-38o'
}, alber@DESKTOP-8CVHP91 MINGW64 ~/Ref label: 'trained',
outV: 4288,
inV: 4200,
properties: {}
},
Vertex { id: 4200, label: 'institution', properties: undefined
},
Edge {
id: { relationId: 'odxco-3b4-27th-3ao'
},
label: 'trained',
outV: 4288,
inV: 4272,
properties: {}
},
Vertex { id: 4272, label: 'institution', properties: undefined
}
]
这不是 bat,我可以使用顶点 ID 和边 inV 来重建关系和 return 我想要的数据,但问题是,如您所见,这个查询return 没有属性。所以有点没用。
但是,通过查看 gremlin 文档,我找到了 valueMap() 步骤,因此我可以像这样稍微编辑之前的查询:
async function getUserTrainings() {
const g = getTraversal();
const result = await g.V()
.hasLabel('user')
.has('identityId', '1234')
.as('u').outE()
.hasLabel('trained')
.inV()
.path()
.unfold()
.where(P.neq('u'))
.valueMap(true)
.toList();
closeConnection();
console.log(result);
}
得到这个输出:
[
Map {
EnumValue { typeName: 'T', elementName: 'id'
} => { relationId: 'odxqw-3b4-27th-38o'
},
'title' => 'Political Science',
EnumValue { typeName: 'T', elementName: 'label'
} => 'trained',
'grade' => 'A'
},
Map {
'name' => [ 'University of Illinois'
],
EnumValue { typeName: 'T', elementName: 'id'
} => 4200,
'identityId' => [ 'IL847'
],
EnumValue { typeName: 'T', elementName: 'label'
} => 'institution'
},
Map {
EnumValue { typeName: 'T', elementName: 'id'
} => { relationId: 'odxco-3b4-27th-3ao'
},
'title' => 'MS in Computer Science',
EnumValue { typeName: 'T', elementName: 'label'
} => 'trained',
'grade' => 'B'
},
Map {
'name' => [ 'University of California'
],
EnumValue { typeName: 'T', elementName: 'id'
} => 4272,
'identityId' => [ 'CA83'
],
EnumValue { typeName: 'T', elementName: 'label'
} => 'institution'
}
]
因此,除了数据 return 编辑的事实外,它一点也不清楚(我的意思是,每个顶点都相同的“typeName:'T'”是什么?),现在我确实取回了属性,但是我松开了边缘的 outV 和 inV,我无法按照我需要的方式重建数据。 (了解哪个顶点由哪条边连接)。
我想我可以只使用第一个查询而不使用 valueMap() 步骤,然后对于我返回的每个顶点和边,将执行另一个查询以使用 id 检索属性。
对于像这样的简单情况,这可能没问题,但我认为这对于可能涉及数百个顶点和边的查询来说并不是很有效。
所以最后一个问题是:从路径重建数据(包括顶点和边属性)的最有效方法是什么?
我将直接进入我认为是你问题核心的问题,因为我认为直接回答可能会澄清其他问题 sub-questions:
let's say I want to retrieve all the trainings that a user took, and I'd also like to have the name of the institution where the training was taken
gremlin> g.V().has('user','identityId', '1234').
......1> outE('trained').
......2> project('institution','title','grade').
......3> by(inV().values('name')).
......4> by('title').
......5> by('grade')
==>[institution:University of California,title:MS in Computer Science,grade:B]
==>[institution:University of Illinois,title:Political Science,grade:A]
我认为需要澄清的一个附带问题:
what is that "typeName: 'T'" that's the same for every vertex?
T
是 Gremlin 中的枚举值,表示图形元素的一些核心结构属性,具体为 label
和 id
.
我正在尝试从图形中重建使用 gremlin 查询检索到的数据。 准确地说,我很难找到一种有效的方法来处理返回的数据。
我使用的 JanusGraph 版本是 0.3.1,它在 Cassandra + ES 上 运行ning,它还配置了 ConfiguredGraphFactory。所以我可以动态创建图表。
我正在使用 gremlin javascript 版本 3.4.2(3.3.3 无法正常工作)
我建立了一个小例子来更好地解释我的意思。 此示例中的图表是在没有模式的情况下创建的。
首先,我将使用以下函数连接到图表:
const gremlin = require('gremlin');
const { Graph } = gremlin.structure;
const { DriverRemoteConnection } = gremlin.driver;
const __ = gremlin.process.statics;
const P = gremlin.process.P;
const GREMLIN_URL = "ws://localhost:8182/gremlin";
const GRAPH_NAME = "graphtest";
let connection;
function getTraversal() {
const graph = new Graph();
connection = new DriverRemoteConnection(GREMLIN_URL, { traversalSource: GRAPH_NAME });
return g = graph.traversal().withRemote(connection);
}
function closeConnection() {
if(connection && connection.close) connection.close();
}
然后我将创建一些顶点和边。
我们将有一个用户、两个机构和两个 'trained' 连接用户和机构的边缘:
async function createVerticesAndEdges() {
const g = getTraversal();
const userV = await g.addV('user').property('name', 'Emily').property('identityId', '1234').next();
console.log('user', userV);
const institutionV = await g.addV('institution').property('name', 'University of California').property('identityId', 'CA83').next();
console.log('institution', institutionV);
const institutionV2 = await g.addV('institution').property('name', 'University of Illinois').property('identityId', 'IL847').next();
console.log('institution2', institutionV2);
const trainedE = await g.addE('trained').property('title', 'MS in Computer Science').property('grade', 'B')
.from_(__.V().has('identityId', '1234')).to(__.V().has('identityId', 'CA83')).next();
console.log('trained', trainedE);
const trainedE2 = await g.addE('trained').property('title', 'Political Science').property('grade', 'A')
.from_(__.V().has('identityId', '1234')).to(__.V().has('identityId', 'IL847')).next();
console.log('trained2', trainedE2);
closeConnection();
}
然后,假设我想检索用户参加的所有培训,我还想知道参加培训的机构的名称。
所以我运行的查询是这样的:
async function getUserTrainings() {
const g = getTraversal();
const result = await g.V()
.hasLabel('user')
.has('identityId', '1234')
.as('u').outE()
.hasLabel('trained')
.inV()
.path()
.unfold()
.where(P.neq('u'))
.toList();
closeConnection();
console.log(result);
}
我得到了这个输出:
[
Edge {
id: { relationId: 'odxqw-3b4-27th-38o'
}, alber@DESKTOP-8CVHP91 MINGW64 ~/Ref label: 'trained',
outV: 4288,
inV: 4200,
properties: {}
},
Vertex { id: 4200, label: 'institution', properties: undefined
},
Edge {
id: { relationId: 'odxco-3b4-27th-3ao'
},
label: 'trained',
outV: 4288,
inV: 4272,
properties: {}
},
Vertex { id: 4272, label: 'institution', properties: undefined
}
]
这不是 bat,我可以使用顶点 ID 和边 inV 来重建关系和 return 我想要的数据,但问题是,如您所见,这个查询return 没有属性。所以有点没用。
但是,通过查看 gremlin 文档,我找到了 valueMap() 步骤,因此我可以像这样稍微编辑之前的查询:
async function getUserTrainings() {
const g = getTraversal();
const result = await g.V()
.hasLabel('user')
.has('identityId', '1234')
.as('u').outE()
.hasLabel('trained')
.inV()
.path()
.unfold()
.where(P.neq('u'))
.valueMap(true)
.toList();
closeConnection();
console.log(result);
}
得到这个输出:
[
Map {
EnumValue { typeName: 'T', elementName: 'id'
} => { relationId: 'odxqw-3b4-27th-38o'
},
'title' => 'Political Science',
EnumValue { typeName: 'T', elementName: 'label'
} => 'trained',
'grade' => 'A'
},
Map {
'name' => [ 'University of Illinois'
],
EnumValue { typeName: 'T', elementName: 'id'
} => 4200,
'identityId' => [ 'IL847'
],
EnumValue { typeName: 'T', elementName: 'label'
} => 'institution'
},
Map {
EnumValue { typeName: 'T', elementName: 'id'
} => { relationId: 'odxco-3b4-27th-3ao'
},
'title' => 'MS in Computer Science',
EnumValue { typeName: 'T', elementName: 'label'
} => 'trained',
'grade' => 'B'
},
Map {
'name' => [ 'University of California'
],
EnumValue { typeName: 'T', elementName: 'id'
} => 4272,
'identityId' => [ 'CA83'
],
EnumValue { typeName: 'T', elementName: 'label'
} => 'institution'
}
]
因此,除了数据 return 编辑的事实外,它一点也不清楚(我的意思是,每个顶点都相同的“typeName:'T'”是什么?),现在我确实取回了属性,但是我松开了边缘的 outV 和 inV,我无法按照我需要的方式重建数据。 (了解哪个顶点由哪条边连接)。
我想我可以只使用第一个查询而不使用 valueMap() 步骤,然后对于我返回的每个顶点和边,将执行另一个查询以使用 id 检索属性。
对于像这样的简单情况,这可能没问题,但我认为这对于可能涉及数百个顶点和边的查询来说并不是很有效。
所以最后一个问题是:从路径重建数据(包括顶点和边属性)的最有效方法是什么?
我将直接进入我认为是你问题核心的问题,因为我认为直接回答可能会澄清其他问题 sub-questions:
let's say I want to retrieve all the trainings that a user took, and I'd also like to have the name of the institution where the training was taken
gremlin> g.V().has('user','identityId', '1234').
......1> outE('trained').
......2> project('institution','title','grade').
......3> by(inV().values('name')).
......4> by('title').
......5> by('grade')
==>[institution:University of California,title:MS in Computer Science,grade:B]
==>[institution:University of Illinois,title:Political Science,grade:A]
我认为需要澄清的一个附带问题:
what is that "typeName: 'T'" that's the same for every vertex?
T
是 Gremlin 中的枚举值,表示图形元素的一些核心结构属性,具体为 label
和 id
.