微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SPARQL如何在RDF图中找到通过多个节点的最短路径

如何解决SPARQL如何在RDF图中找到通过多个节点的最短路径

如何使用sparql设置多个节点并找到通过每个节点的最短路径?可以使用Cypher实现此功能。但是,我不知道如何通过Sparql实现它,以便我可以在Jena中查询路径。

解决方法

非常感谢您的帮助!最后,我修改了耶拿(Jena)的java api函数(findShortestPath)以实现此功能。

首先,为了实现任何两个节点之间的最短路径查询(无论关系的方向如何),我如下修改了jena(findShortestPath)的java api函数。

private JSONObject findShortestPath(Model m,Resource start,Resource end) {
        int shortestLength = 20;
        JSONObject pathResult = new JSONObject();
        pathResult.put("length",shortestLength);
        pathResult.put("paths",new JSONArray());

        List<OntTools.Path> bfs = new LinkedList<>();
        ArrayList<ExtendedIterator> nodeStatementIter = new ArrayList<>();
        nodeStatementIter.add(m.listStatements(start,null,(RDFNode)null));
        nodeStatementIter.add(m.listStatements(null,start));
        for (var iter : nodeStatementIter) {
            while(iter.hasNext()) {
                Statement statement = (Statement) iter.next();
                if (! statement.getObject().isLiteral())
                bfs.add((new OntTools.Path()).append(statement));
            }
        }
        nodeStatementIter.clear();

        HashSet<Resource> passedNodes = new HashSet<>();
        passedNodes.add(start);

        while(!bfs.isEmpty()) {
            OntTools.Path candidate = bfs.remove(0);
            if (candidate.size() > shortestLength) {
                break;
            }

            Resource subject = candidate.getStatement(candidate.size() - 1).getSubject();
            Resource object = candidate.getStatement(candidate.size() - 1).getObject().isResource() ? candidate.getStatement(candidate.size() - 1).getObject().asResource() : null;
            ArrayList<Resource> resources = new ArrayList<>();
            resources.add(subject);
            if (object != null) {
                resources.add(object);
            }

            if (resources.contains(end)) {
//                solution = candidate;
                shortestLength = candidate.size();
                pathResult.put("length",shortestLength);
                pathResult.getJSONArray("paths").add(pathToTriples(candidate));
            } else {

                for (Resource resource : resources) {
                    if (! passedNodes.contains(resource)) {
                        nodeStatementIter.add(m.listStatements(resource,(RDFNode)null));
                        nodeStatementIter.add(m.listStatements(null,resource));
                        passedNodes.add(resource);
                        for (var iter : nodeStatementIter) {
                            while(iter.hasNext()) {
//                                Statement link = (Statement)iter.next();
                                Statement statement = (Statement) iter.next();
                                if (!candidate.contains(statement))
                                    bfs.add(candidate.append(statement));
                            }
                        }
                        nodeStatementIter.clear();
                    }
                }
            }
        }

        if (pathResult.getJSONArray("paths").size() == 0) {
            pathResult.put("length",Integer.MAX_VALUE);
        }

        return pathResult;
    }

在此函数中,另一个函数用于将路径转换为三元组

private ArrayList<ArrayList<String>> pathToTriples(OntTools.Path path) {
        ListIterator<Statement> statementListIterator = path.listIterator();
        ArrayList<ArrayList<String>> statements = new ArrayList<>();
        while (statementListIterator.hasNext()) {
            Statement next = statementListIterator.next();
            statements.add(new ArrayList<>(){{
                add(next.getSubject().toString());
                add(next.getPredicate().toString());
                add(next.getObject().toString());
            }});
        }
        return statements;
    }

最后,为了实现通过多个指定节点的最短路径查询,我列举了节点序列的可能组合。然后,计算每种组合的每两个节点之间的最短路径之和,并选择总长度最短的所有组合作为最终结果。

public JSONObject findShortestPathBetweenMultipleNodes(Model m,List<Resource> nodes) {
        ArrayList<ArrayList<JSONArray>> nodePairPathMatrix = new ArrayList<>();
        ArrayList<ArrayList<Integer>> nodePairLengthMatrix = new ArrayList<>();

        for (int i = 0; i < nodes.size(); i++) {
            nodePairPathMatrix.add(new ArrayList<>(){{
                for (int j = 0; j < nodes.size(); j++) {
                    add(null);
                }
            }});
            nodePairLengthMatrix.add(new ArrayList<>(){{
                for (int j = 0; j < nodes.size(); j++) {
                    add(Integer.MAX_VALUE);
                }
            }});
        }


        for (int i = 0; i < nodes.size()-1; i++) {
            for (int j = i+1; j < nodes.size(); j++) {
                Resource source = nodes.get(i);
                Resource target = nodes.get(j);
                JSONObject shortestPath = findShortestPath(m,source,target);
                JSONArray paths = shortestPath.getJSONArray("paths");

                nodePairPathMatrix.get(i).set(j,paths);
                nodePairPathMatrix.get(j).set(i,paths);
                nodePairLengthMatrix.get(i).set(j,shortestPath.getInteger("length"));
                nodePairLengthMatrix.get(j).set(i,shortestPath.getInteger("length"));
            }
        }

        ArrayList<ArrayList<Integer>> permutationsOfNodes = permutationByMaxNum(nodes.size());
        Integer minLength = Integer.MAX_VALUE;
        ArrayList<ArrayList<JSONArray>> nodePairPathListWithMinLength = new ArrayList<>();
        for (var permutation : permutationsOfNodes){
            Integer length = 0;
            ArrayList<JSONArray> nodePairPathList = new ArrayList<>();
            for (int permutationItemIndex = 1; permutationItemIndex < permutation.size(); permutationItemIndex++) {
                int end = permutation.get(permutationItemIndex);
                int start = permutation.get(permutationItemIndex-1);
                Integer curNodePairLength = nodePairLengthMatrix.get(start).get(end);
                if (curNodePairLength.equals(Integer.MAX_VALUE) || nodePairLengthMatrix.get(start).get(end).equals(Integer.MAX_VALUE)){
                    length = Integer.MAX_VALUE;
                    break;
                }
                length += nodePairLengthMatrix.get(start).get(end);
                nodePairPathList.add(nodePairPathMatrix.get(start).get(end));
            }
            if (length < minLength) {
                minLength = length;
                nodePairPathListWithMinLength.clear();
                nodePairPathListWithMinLength.add(nodePairPathList);
            } else if (length.equals(minLength)) {
                nodePairPathListWithMinLength.add(nodePairPathList);
            }
        }

        Set<List<String>> tripleResults = new HashSet<>();
        for (var equalTotalLengthNodePairPathListWithMinLength : nodePairPathListWithMinLength) {
            for (var nodePairPathList : equalTotalLengthNodePairPathListWithMinLength) {
                for (int i = 0; i < nodePairPathList.size(); i++) {
                    JSONArray nodePairPathWithEqualLength = nodePairPathList.getJSONArray(i);
                    for (int j = 0; j < nodePairPathWithEqualLength.size(); j++) {
                        JSONArray nodePairPath = nodePairPathWithEqualLength.getJSONArray(j);
                        List<String> triple = nodePairPath.toJavaList(String.class);
                        tripleResults.add(triple);
                    }
                }
            }
        }
        JSONObject result = new JSONObject();
        result.put("triples",tripleResults);
        result.put("length",minLength);

        return result;
    }

节点的排列是由以下函数生成的。

    private ArrayList<ArrayList<Integer>> permutationByMaxNum (int maxNum) {
        Stack<Integer> stack = new Stack<>();
        ArrayList<ArrayList<Integer>> results = new ArrayList<>();

        ArrayList<Integer> sourceList = new ArrayList<>();
        for (int i = 0; i < maxNum; i++) {
            sourceList.add(i);
        }
        permutateFunction(results,sourceList,maxNum,stack);
        return results;
    }

    private static void permutateFunction(ArrayList<ArrayList<Integer>> results,ArrayList<Integer> sourceList,int targetNumber,int curNumber,Stack<Integer> stack) {
        if(curNumber == targetNumber) {
//            System.out.println(stack);
            results.add(new ArrayList<>(stack));
            return;
        }

        for (int j : sourceList) {
            if (!stack.contains(j)) {
                stack.add(j);
                permutateFunction(results,targetNumber,curNumber + 1,stack);
                stack.pop();
            }
        }
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?