diff --git a/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphImpl.java b/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphImpl.java index 0afebfb2..8b57fbe7 100644 --- a/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphImpl.java +++ b/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphImpl.java @@ -173,8 +173,22 @@ public class KgGraphImpl implements KgGraph, Serializable { Long limit) { Set vertexAliases = Sets.newHashSet(inputVertexAliases); - // remove alias that vertex set size is 1 - vertexAliases.removeIf(vertexAlias -> 1 == this.alias2VertexMap.get(vertexAlias).size()); + // remove alias that vertex set size is 1 and its related edge size is 1 + Map> vertexAliasToEdgeAliasMap = + staticParameters.getVertexAliasToEdgeAliasMap(); + vertexAliases.removeIf( + vertexAlias -> { + Boolean isSingleVertex = 1 == this.alias2VertexMap.get(vertexAlias).size(); + Set relatedEdgeAliasSet = vertexAliasToEdgeAliasMap.get(vertexAlias); + Boolean isRelatedEdgeSingle = true; + for (String edgeAlias : relatedEdgeAliasSet) { + isRelatedEdgeSingle = 1 == this.alias2EdgeMap.get(edgeAlias).size(); + if (!isRelatedEdgeSingle) { + break; + } + } + return isSingleVertex && isRelatedEdgeSingle; + }); if (vertexAliases.isEmpty()) { // not need split if (null != filter && !filter.test(this)) { @@ -201,8 +215,7 @@ public class KgGraphImpl implements KgGraph, Serializable { return resultList; } - Map> resultMap = new HashMap<>(); - List vertexAliasList = Lists.newArrayList(vertexAliases); + List> result = new ArrayList<>(); EdgeCombinationIterator it = new EdgeCombinationIterator( staticParameters.getEdgeIterateInfoList(), @@ -218,15 +231,13 @@ public class KgGraphImpl implements KgGraph, Serializable { if (null != filter && !filter.test(path)) { continue; } - Bytes key = getKgGraphKeyBySplitVertex(vertexAliasList, path); - KgGraph kgGraph = resultMap.computeIfAbsent(key, k -> new KgGraphImpl()); - kgGraph.merge(Lists.newArrayList(path), schema); - if (null != limit && resultMap.size() >= limit) { + result.add(path); + if (null != limit && result.size() >= limit) { // reach max path limit break; } } - return Lists.newArrayList(resultMap.values()); + return result; } /** @@ -419,8 +430,7 @@ public class KgGraphImpl implements KgGraph, Serializable { alias2VertexMap, alias2EdgeMap); it.setScope(limit); - List sortedVertexAliasList = Lists.newArrayList(vertexAliases); - Map> result = new HashMap<>(); + List> result = new ArrayList<>(); long count = 0; while (it.hasNext()) { KgGraph kgg = it.next(); @@ -436,29 +446,12 @@ public class KgGraphImpl implements KgGraph, Serializable { if (kgGraph.checkDuplicateVertex()) { continue; } - - KgGraphKey kgGraphKey = getKgGraphKey(kgGraph, sortedVertexAliasList); - KgGraph oldKgGraph = result.get(kgGraphKey); - if (null == oldKgGraph) { - result.put(kgGraphKey, kgGraph); - } else { - oldKgGraph.merge(Lists.newArrayList(kgGraph), schema); - } + result.add(kgGraph); if (null != limit && count >= limit) { break; } } - return Lists.newArrayList(result.values()); - } - - private KgGraphKey getKgGraphKey(KgGraph kgGraph, List vertexAliases) { - IVertexId[] vertexIds = new IVertexId[vertexAliases.size()]; - for (int i = 0; i < vertexAliases.size(); ++i) { - String alias = vertexAliases.get(i); - IVertexId vertexId = kgGraph.getVertex(alias).get(0).getId(); - vertexIds[i] = vertexId; - } - return new KgGraphKey(vertexIds); + return result; } /** diff --git a/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphKey.java b/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphKey.java deleted file mode 100644 index 4216e12d..00000000 --- a/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphKey.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2023 OpenSPG Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. - */ - -package com.antgroup.openspg.reasoner.kggraph.impl; - -import com.antgroup.openspg.reasoner.common.graph.vertex.IVertexId; -import java.util.Arrays; - -public class KgGraphKey { - private final IVertexId[] vertexIds; - - public KgGraphKey(IVertexId[] vertexIds) { - this.vertexIds = vertexIds; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof KgGraphKey)) { - return false; - } - KgGraphKey other = (KgGraphKey) obj; - return Arrays.equals(this.vertexIds, other.vertexIds); - } - - @Override - public int hashCode() { - return Arrays.hashCode(vertexIds); - } -} diff --git a/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphSplitStaticParameters.java b/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphSplitStaticParameters.java index 16a3656b..74206283 100644 --- a/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphSplitStaticParameters.java +++ b/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/kggraph/impl/KgGraphSplitStaticParameters.java @@ -56,10 +56,13 @@ public class KgGraphSplitStaticParameters implements Serializable { private final List subEdgeIterateInfoList; private final Map subEdgeIterateOrderMap; - /** 将KgGraph中重复调用的逻辑抽出来,在初始化中一次完成 */ + private final Map> vertexAliasToEdgeAliasMap; + + // Abstract the logic of repeated calls in KgGraph and do it all at once in initialization public KgGraphSplitStaticParameters(Set splitVertexAliases, Pattern schema) { this.edgeIterateInfoList = initEdgeIterateInfo(schema); this.edgeIterateOrderMap = initEdgeIterateOrderMap(this.edgeIterateInfoList); + this.vertexAliasToEdgeAliasMap = parseVertexAliasToEdgeAliasMap(schema); if (CollectionUtils.isNotEmpty(splitVertexAliases)) { this.needSplitEdgeSet = getNeedSplitEdgeSet(splitVertexAliases, schema); @@ -96,6 +99,23 @@ public class KgGraphSplitStaticParameters implements Serializable { } } + private static Map> parseVertexAliasToEdgeAliasMap(Pattern schema) { + Map> vertexAliasToEdgeAliasMap = new HashMap<>(); + for (String key : JavaConversions.setAsJavaSet(schema.topology().keySet())) { + scala.collection.Iterator it = schema.topology().get(key).get().iterator(); + while (it.hasNext()) { + Connection connection = it.next(); + Set sourceVertexRelatedEdgeAliasSet = + vertexAliasToEdgeAliasMap.computeIfAbsent(connection.source(), k -> new HashSet<>()); + sourceVertexRelatedEdgeAliasSet.add(connection.alias()); + Set targetVertexRelatedEdgeAliasSet = + vertexAliasToEdgeAliasMap.computeIfAbsent(connection.target(), k -> new HashSet<>()); + targetVertexRelatedEdgeAliasSet.add(connection.alias()); + } + } + return vertexAliasToEdgeAliasMap; + } + /** * Getter method for property needSplitEdgeSet. * @@ -168,6 +188,15 @@ public class KgGraphSplitStaticParameters implements Serializable { return subEdgeIterateOrderMap; } + /** + * Getter method for property vertexAliasToEdgeAliasMap. + * + * @return property value of vertexAliasToEdgeAliasMap + */ + public Map> getVertexAliasToEdgeAliasMap() { + return vertexAliasToEdgeAliasMap; + } + public boolean canDoSampleSplit(Map>> alias2VertexMap) { if (null == this.neighborAliasSet) { return false; diff --git a/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/rdg/common/UnfoldReduceDuplicateImpl.java b/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/rdg/common/UnfoldReduceDuplicateImpl.java index b62dc4eb..f6f49c1a 100644 --- a/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/rdg/common/UnfoldReduceDuplicateImpl.java +++ b/reasoner/runner/runner-common/src/main/java/com/antgroup/openspg/reasoner/rdg/common/UnfoldReduceDuplicateImpl.java @@ -17,34 +17,75 @@ import com.antgroup.openspg.reasoner.common.graph.edge.IEdge; import com.antgroup.openspg.reasoner.common.graph.property.IProperty; import com.antgroup.openspg.reasoner.common.graph.vertex.IVertexId; import com.antgroup.openspg.reasoner.kggraph.KgGraph; +import com.antgroup.openspg.reasoner.lube.common.pattern.Connection; import com.antgroup.openspg.reasoner.lube.common.pattern.Pattern; +import com.antgroup.openspg.reasoner.utils.RunnerUtil; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; public class UnfoldReduceDuplicateImpl implements KgGraphListProcess { - private final Pattern schema; private final String edgeAlias; + private final List edgeAliasList = new ArrayList<>(); public UnfoldReduceDuplicateImpl(Pattern schema, String edgeAlias) { - this.schema = schema; this.edgeAlias = edgeAlias; + for (Connection connection : RunnerUtil.getConnectionSet(schema)) { + if (connection.alias().equals(this.edgeAlias)) { + continue; + } + this.edgeAliasList.add(connection.alias()); + } } @Override public List> reduce(Collection> kgGraphs) { - Set> pathEdgeSet = new HashSet<>(); + Set pathEdgeKeySet = new HashSet<>(); List> result = new ArrayList<>(); for (KgGraph kgGraph : kgGraphs) { - IEdge edge = kgGraph.getEdge(edgeAlias).get(0); - if (pathEdgeSet.contains(edge)) { + PathDuplicateKey key = new PathDuplicateKey(kgGraph); + if (pathEdgeKeySet.contains(key)) { continue; } - pathEdgeSet.add(edge); + pathEdgeKeySet.add(key); result.add(kgGraph); } return result; } + + private class PathDuplicateKey { + private final List> edgeList = new ArrayList<>(); + + public PathDuplicateKey(KgGraph kgGraph) { + addEdges(kgGraph); + } + + public void addEdges(KgGraph kgGraph) { + this.edgeList.add(kgGraph.getEdge(edgeAlias).get(0)); + for (String edgeAlias : edgeAliasList) { + IEdge edge = kgGraph.getEdge(edgeAlias).get(0); + this.edgeList.add(edge); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PathDuplicateKey that = (PathDuplicateKey) o; + return Arrays.equals(this.edgeList.toArray(), that.edgeList.toArray()); + } + + @Override + public int hashCode() { + return Arrays.hashCode(this.edgeList.toArray()); + } + } } diff --git a/reasoner/runner/runner-common/src/test/java/com/antgroup/openspg/reasoner/kggraph/KgGraphSimpleSplitTest.java b/reasoner/runner/runner-common/src/test/java/com/antgroup/openspg/reasoner/kggraph/KgGraphSimpleSplitTest.java index 96c9d4f6..86737c64 100644 --- a/reasoner/runner/runner-common/src/test/java/com/antgroup/openspg/reasoner/kggraph/KgGraphSimpleSplitTest.java +++ b/reasoner/runner/runner-common/src/test/java/com/antgroup/openspg/reasoner/kggraph/KgGraphSimpleSplitTest.java @@ -46,6 +46,7 @@ public class KgGraphSimpleSplitTest { Pattern schema = pattern1(); KgGraph kgGraph = kgGraph1(); + // B,C,D size is 1, but its adjacent edge is more than 1 Set splitVertexAliasSet = Sets.newHashSet("B", "C", "D"); List> rst1 = kgGraph.split( @@ -54,9 +55,9 @@ public class KgGraphSimpleSplitTest { new KgGraphSplitStaticParameters(splitVertexAliasSet, schema), null, null); - Assert.assertEquals(1, rst1.size()); - Assert.assertEquals(rst1.get(0), kgGraph); + Assert.assertEquals(2, rst1.size()); + // D size is 1 and its adjacent edge is 1 Set splitVertexAliasSet2 = Sets.newHashSet("D"); List> rst2 = kgGraph.split( @@ -207,11 +208,11 @@ public class KgGraphSimpleSplitTest { new KgGraphSplitStaticParameters(splitVertexAliasSet3, schema), null, null); - Assert.assertEquals(2, rst3.size()); + Assert.assertEquals(4, rst3.size()); rst3.stream() .forEach( iVertexIdKgGraph -> { - Assert.assertEquals(2, iVertexIdKgGraph.getVertex("A").size()); + Assert.assertEquals(1, iVertexIdKgGraph.getVertex("A").size()); Assert.assertEquals(1, iVertexIdKgGraph.getVertex("B").size()); Assert.assertEquals(1, iVertexIdKgGraph.getVertex("C").size()); Assert.assertEquals(1, iVertexIdKgGraph.getVertex("D").size()); diff --git a/reasoner/runner/runner-common/src/test/java/com/antgroup/openspg/reasoner/kggraph/KgGraphTest.java b/reasoner/runner/runner-common/src/test/java/com/antgroup/openspg/reasoner/kggraph/KgGraphTest.java index 51b0be43..7b0a5fd1 100644 --- a/reasoner/runner/runner-common/src/test/java/com/antgroup/openspg/reasoner/kggraph/KgGraphTest.java +++ b/reasoner/runner/runner-common/src/test/java/com/antgroup/openspg/reasoner/kggraph/KgGraphTest.java @@ -98,7 +98,8 @@ public class KgGraphTest { new KgGraphSplitStaticParameters(splitVertexAliasSet2, schemaB), null, null); - Assert.assertTrue(splitRst.size() == kgGraph.getAlias2VertexMap().get("B").size()); + // B size is 1, but its adjacent edge size is more than 1 + Assert.assertTrue(splitRst.size() == 2); splitRst.stream() .map(kgGraph -> ((KgGraphImpl) kgGraph)) .forEach(kgGraph -> Assert.assertTrue(kgGraph.getAlias2VertexMap().get("B").size() == 1));