Skip to content

Commit 7e5988c

Browse files
Merge pull request #819 from RedisInsight/redisgraph-fix-relationship-duplication
[RedisGraph] Fix relationship duplication
2 parents ce35f64 + 206ab2d commit 7e5988c

File tree

3 files changed

+52
-20
lines changed

3 files changed

+52
-20
lines changed

redisinsight/ui/src/packages/redisgraph/src/Graph.tsx

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
getFetchNodesByIdQuery,
1515
getFetchDirectNeighboursOfNodeQuery,
1616
getFetchNodeRelationshipsQuery,
17+
getFetchEdgesByIdQuery,
1718
} from './utils'
1819
import {
1920
EDGE_COLORS,
@@ -56,7 +57,7 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
5657
let nodeIds = new Set(parsedResponse.nodes.map(n => n.id))
5758
let edgeIds = new Set(parsedResponse.edges.map(e => e.id))
5859

59-
if (nodeIds.size === 0 && parsedResponse.nodeIds.length === 0) {
60+
if (nodeIds.size === 0 && parsedResponse.nodeIds.size === 0) {
6061
return <div className="responseInfo">No data to visualize. Switch to Text view to see raw information.</div>
6162
}
6263

@@ -87,18 +88,29 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
8788
let newNodeLabels: {[key: string]: number} = nodeLabels
8889
let newEdgeTypes: {[key: string]: number} = edgeTypes
8990

90-
if (parsedResponse.nodeIds.length > 0) {
91+
if (parsedResponse.hasNamedPathItem && parsedResponse.npNodeIds.length > 0) {
9192
try {
9293
/* Fetch named path nodes */
93-
const resp = await executeRedisCommand(getFetchNodesByIdQuery(props.graphKey, [...parsedResponse.nodeIds]))
94-
94+
let resp = await executeRedisCommand(getFetchNodesByIdQuery(props.graphKey, [...parsedResponse.npNodeIds]))
9595
if (Array.isArray(resp) && (resp.length >= 1 || resp[0].status === 'success')) {
9696
const parsedData = responseParser(resp[0].response)
9797
parsedData.nodes.forEach(n => {
9898
nodeIds.add(n.id)
9999
n.labels.forEach(l => newNodeLabels[l] = (newNodeLabels[l] + 1) || 1)
100100
})
101-
parsedData.edges.forEach(e => newEdgeTypes[e.type] = (newEdgeTypes[e.type] + 1) || 1)
101+
102+
resp = await executeRedisCommand(getFetchEdgesByIdQuery(props.graphKey, [...parsedResponse.npEdgeIds]))
103+
if (Array.isArray(resp) && (resp.length >= 1 || resp[0].status === 'success')) {
104+
const edgeParsedData = responseParser(resp[0].response)
105+
parsedData.edges = [...edgeParsedData.edges]
106+
parsedData.edgeIds = edgeParsedData.edgeIds
107+
}
108+
109+
parsedData.edges = parsedData.edges.filter(e => !edgeIds.has(e.id))
110+
parsedData.edges.forEach(e => {
111+
edgeIds.add(e.id)
112+
newEdgeTypes[e.type] = (newEdgeTypes[e.type] + 1) || 1
113+
})
102114

103115
newGraphData = {
104116
...newGraphData,
@@ -111,7 +123,7 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
111123
nodes: parsedData.nodes,
112124
relationships: parsedData
113125
.edges
114-
.filter(e => nodeIds.has(e.source) && nodeIds.has(e.target) && !edgeIds.has(e.id))
126+
.filter(e => nodeIds.has(e.source) && nodeIds.has(e.target))
115127
.map(e => ({ ...e, startNode: e.source, endNode: e.target }))
116128
}
117129
}]
@@ -124,7 +136,7 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
124136

125137
try {
126138
/* Fetch neighbours automatically */
127-
const resp = await executeRedisCommand(getFetchNodeRelationshipsQuery(props.graphKey, [...nodeIds], [...nodeIds]))
139+
const resp = await executeRedisCommand(getFetchNodeRelationshipsQuery(props.graphKey, [...nodeIds], [...nodeIds], [...edgeIds]))
128140

129141
if (Array.isArray(resp) && (resp.length >= 1 || resp[0].status === 'success')) {
130142
const parsedData = responseParser(resp[0].response)
@@ -134,8 +146,10 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
134146
})
135147
const filteredEdges = parsedData
136148
.edges
137-
.filter(e => nodeIds.has(e.source) && nodeIds.has(e.target) && !edgeIds.has(e.id))
149+
.filter(e => !edgeIds.has(e.id))
150+
.filter(e => nodeIds.has(e.source) && nodeIds.has(e.target))
138151
.map(e => {
152+
edgeIds.add(e.id)
139153
newEdgeTypes[e.type] = (newEdgeTypes[e.type] + 1 || 1)
140154
return ({ ...e, startNode: e.source, endNode: e.target, fetchedAutomatically: true })
141155
})
@@ -200,7 +214,10 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
200214
n.labels.forEach(l => newNodeLabels[l] = (newNodeLabels[l] + 1) || 1)
201215
})
202216
const filteredEdges = parsedData.edges.filter(e => !edgeIds.has(e.id)).map(e => ({ ...e, startNode: e.source, endNode: e.target }))
203-
filteredEdges.forEach(e => newEdgeTypes[e.type] = (newEdgeTypes[e.type] + 1) || 1)
217+
filteredEdges.forEach(e => {
218+
edgeIds.add(e.id)
219+
newEdgeTypes[e.type] = (newEdgeTypes[e.type] + 1) || 1
220+
})
204221

205222
graphd3.updateWithGraphData({
206223
results: [{

redisinsight/ui/src/packages/redisgraph/src/parser.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,16 @@ function responseParser(data: any) {
3737

3838
const headers = data[0]
3939
let nodes: INode[] = []
40-
let nodeIds: string[] = []
41-
let edgeIds: string[] = []
40+
let nodeIds = new Set<string>()
41+
let edgeIds = new Set<string>()
4242
let edges: IEdge[] = []
4343
let types: {[key: string]: number} = {}
4444
let labels: {[key: string]: number} = {}
45+
let hasNamedPathItem = false
46+
let npNodeIds: string[] = []
47+
let npEdgeIds: string[] = []
4548
if (data.length < 2) return {
46-
nodes, edges, types, labels, headers, nodeIds, edgeIds,
49+
nodes, edges, types, labels, headers, nodeIds, edgeIds, hasNamedPathItem,
4750
}
4851

4952
const entries = data[1].map((entry: any) => {
@@ -79,16 +82,22 @@ function responseParser(data: any) {
7982
const v = resolveProps(x)
8083
edge['properties'][v.key] = v.value
8184
})
82-
edges.push(edge)
85+
if (!edgeIds.has(edge.id)) {
86+
edges.push(edge)
87+
edgeIds.add(edge.id)
88+
}
8389
} else {
8490
// unknown item?
8591
}
8692
} else if (typeof(item) === 'string'){
8793
try {
8894
// If named path response, try to parse it
89-
let [nIds, eIds] = ParseEntitesFromNamedPathResponse(item)
90-
nodeIds = Array.from(new Set(nodeIds.concat(nIds)))
91-
edgeIds = Array.from(new Set(edgeIds.concat(eIds)))
95+
hasNamedPathItem = true
96+
let[nIds, eIds] = ParseEntitesFromNamedPathResponse(item)
97+
nodeIds = new Set([...nodeIds, ...nIds])
98+
edgeIds = new Set([...edgeIds, ...eIds])
99+
npNodeIds = [...nodeIds]
100+
npEdgeIds = [...edgeIds]
92101
} catch {
93102
// maybe just a normal string
94103
}
@@ -104,6 +113,9 @@ function responseParser(data: any) {
104113
labels,
105114
nodeIds,
106115
edgeIds,
116+
hasNamedPathItem,
117+
npNodeIds,
118+
npEdgeIds,
107119
}
108120
}
109121

redisinsight/ui/src/packages/redisgraph/src/utils.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,16 +184,19 @@ export function wrapText(s: string, w: number) {
184184
}
185185

186186

187-
export function getFetchNodesByIdQuery(graphKey: string, nodeIds: Array<string>): string {
188-
return `graph.ro_query ${graphKey} "MATCH (n) WHERE id(n) IN [${nodeIds}] RETURN n"`
187+
export function getFetchNodesByIdQuery(graphKey: string, nodeIds: string[]): string {
188+
return `graph.ro_query ${graphKey} "MATCH (n) WHERE id(n) IN [${nodeIds}] RETURN DISTINCT n"`
189189
}
190190

191+
export function getFetchEdgesByIdQuery(graphKey: string, edgeIds: string[]): string {
192+
return `graph.ro_query ${graphKey} "MATCH ()-[t]->() WHERE id(t) IN [${edgeIds}] RETURN DISTINCT t"`
193+
}
191194

192195
export function getFetchDirectNeighboursOfNodeQuery(graphKey: string, nodeId: string): string {
193196
return `graph.ro_query "${graphKey}" "MATCH (n)-[t]-(m) WHERE id(n)=${nodeId} RETURN t, m"`
194197
}
195198

196199

197-
export function getFetchNodeRelationshipsQuery(graphKey: string, sourceNodeIds: string[], destNodeIds: string[]): string {
198-
return `graph.ro_query ${graphKey} "MATCH (n)-[t]->(m) WHERE ID(n) IN [${sourceNodeIds}] OR ID(m) IN [${destNodeIds}] RETURN DISTINCT t"`
200+
export function getFetchNodeRelationshipsQuery(graphKey: string, sourceNodeIds: string[], destNodeIds: string[], existingEdgeIds: string[]): string {
201+
return `graph.ro_query ${graphKey} "MATCH (n)-[t]->(m) WHERE (ID(n) IN [${sourceNodeIds}] OR ID(m) IN [${destNodeIds}]) AND NOT ID(t) IN [${existingEdgeIds}] RETURN DISTINCT t"`
199202
}

0 commit comments

Comments
 (0)