/** * @param queryEdge * @param graphEdge * @param r * @return */ protected boolean edgeMatch(Edge queryEdge, Edge graphEdge, IsomorphicQuery r) { if (queryEdge.getLabel() != 0L && queryEdge.getLabel() != graphEdge.getLabel().longValue()) { return false; } Long querySource = null; Long queryDestination = null; Long graphSource = null; Long graphDestination = null; if (r != null) { if (r.isUsing(graphEdge)) { return false; } querySource = queryEdge.getSource(); graphSource = graphEdge.getSource(); boolean mappedSource = r.hasMapped(querySource); boolean usingSource = r.isUsing(graphSource); if (usingSource && !mappedSource) { return false; } queryDestination = queryEdge.getDestination(); graphDestination = graphEdge.getDestination(); boolean mappedDestination = r.hasMapped(queryDestination); boolean usingDestination = r.isUsing(graphDestination); if (usingDestination && !mappedDestination) { return false; } if (mappedSource && !graphSource.equals(r.isomorphicMapOf(querySource).getNodeID())) { return false; } if (mappedDestination && !graphDestination.equals(r.isomorphicMapOf(queryDestination).getNodeID())) { return false; } if (usingSource && !r.mappedAs(graphSource).equals(querySource)) { return false; } if (usingDestination && !r.mappedAs(graphDestination).equals(queryDestination)) { return false; } } return true; }
/** * Checks if, for a given node, it exist an <b>outgoing</b> with that label and returns all the * graphEdges found * * @param label the label we are looking for * @param graphEdges the knoweldgebase graphEdges * @return labeled graphEdges, can be empty */ public static List<Edge> findEdges(Long label, Collection<Edge> graphEdges) { // Compare to the graphEdges in the KB exiting from the mapped node passed List<Edge> edges = new ArrayList<>(); for (Edge Edge : graphEdges) { if (label == Edge.GENERIC_EDGE_LABEL || Edge.getLabel().longValue() == label || label == 0L) { edges.add(Edge); } } return edges; }
/** * Given a query, a starting node from the query, and a node from the knowledgeBase , tries to * build up a related query * * @param query * @param queryNode * @param graphNode * @return */ public List<IsomorphicQuery> createQueries( Multigraph query, Long queryNode, MappedNode graphNode, IsomorphicQuery relatedQuery) { // Initialize the queries set // Given the current situation we expect to build more than one possible related query List<IsomorphicQuery> relatedQueries = new ArrayList<>(); relatedQueries.add(relatedQuery); // The graphEdges exiting from the query node passed Collection<Edge> queryEdgesOut = query.outgoingEdgesOf(queryNode); // The graphEdges entering the query node passed Collection<Edge> queryEdgesIn = query.incomingEdgesOf(queryNode); // The graphEdges in the KB exiting from the mapped node passed Collection<Edge> graphEdgesOut = graph.outgoingEdgesOf(graphNode.getNodeID()); // The graphEdges in the KB entering the mapped node passed Collection<Edge> graphEdgesIn = graph.incomingEdgesOf(graphNode.getNodeID()); // System.out.println(graphNode.getNodeID() + " " + (graphEdgesOut.size() + // graphEdgesIn.size())); // Null handling queryEdgesIn = queryEdgesIn == null ? new HashSet<Edge>() : queryEdgesIn; queryEdgesOut = queryEdgesOut == null ? new HashSet<Edge>() : queryEdgesOut; graphEdgesIn = graphEdgesIn == null ? new HashSet<Edge>() : graphEdgesIn; graphEdgesOut = graphEdgesOut == null ? new HashSet<Edge>() : graphEdgesOut; // debug("TEst %d map to %d", queryNode, graphNode); // Optimization: if the queryEdges are more than the kbEdges, we are done, not isomorphic! if (queryEdgesIn.size() > graphEdgesIn.size() || queryEdgesOut.size() > graphEdgesOut.size()) { return null; } // All non mapped graphEdges from the query are put in one set Set<Edge> queryEdges = new HashSet<>(); for (Edge edgeOut : queryEdgesOut) { if (!relatedQuery.hasMapped(edgeOut)) { queryEdges.add(edgeOut); } } for (Edge edgeIn : queryEdgesIn) { if (!relatedQuery.hasMapped(edgeIn)) { queryEdges.add(edgeIn); } } queryEdgesIn = null; queryEdgesOut = null; List<Edge> sortedEdges = sortEdge(queryEdges, this.labelFreq); // Look if we can map all the outgoing/ingoing graphEdges of the query node for (Edge queryEdge : sortedEdges) { // System.out.println("Processs answer number: " + relatedQueries.size()); if (relatedQueries.size() > MAX_RELATED) return relatedQueries; // System.out.println(queryEdge); // info("Trying to map the edge " + queryEdge); List<IsomorphicQuery> newRelatedQueries = new ArrayList<>(); LinkedList<IsomorphicQuery> toTestRelatedQueries = new LinkedList<>(); for (IsomorphicQuery current : relatedQueries) { if (current.hasMapped(queryEdge)) { newRelatedQueries.add(current); } else { toTestRelatedQueries.add(current); } } relatedQueries.clear(); IsomorphicQuerySearch.interNum = Math.max(toTestRelatedQueries.size(), IsomorphicQuerySearch.interNum); // reset, we do not want too many duplicates relatedQueries = new LinkedList<>(); // If all candidated have this QueryEdge mapped, go to next if (toTestRelatedQueries.isEmpty()) { relatedQueries = newRelatedQueries; continue; } // The label we are looking for Long label = queryEdge.getLabel(); // is it isIncoming or outgoing ? boolean isIncoming = queryEdge.getDestination().equals(queryNode); List<Edge> graphEdges; // Look for graphEdges with the same label and same direction as the one from the query if (isIncoming) { graphEdges = findEdges(label, graphEdgesIn); } else { graphEdges = findEdges(label, graphEdgesOut); } // loggable.debug("Matching with %d graphEdges", graphEdges.size() ); // Do we found any? if (graphEdges.isEmpty()) { // If we cannot map graphEdges, this path is wrong return null; } else { // Cycle through all the possible graphEdges options, // they would be possibly different related queries for (Edge graphEdge : graphEdges) { // Cycle through all the possible related queries retrieved up to now // A new related query is good if it finds a match for (IsomorphicQuery tempRelatedQuery : toTestRelatedQueries) { if (newRelatedQueries.size() > MAX_RELATED || watch.getElapsedTimeMillis() > QUIT_TIME) { // System.out.println("Time limit exceeded or more than 10000 // partial results"); this.isQuit = true; return relatedQueries.size() > 0 ? relatedQueries : null; } if (tempRelatedQuery.isUsing(graphEdge)) { // Ok this option is already using this edge, // not a good choice go away // it means that this query didn't found his match in this edge continue; } Utilities.searchCount++; // Otherwise this edge can be mapped to the query edge if all goes well IsomorphicQuery newRelatedQuery = tempRelatedQuery.getClone(); // check nodes similarity // double nodeSimilarity = 0; // if (isIncoming) { // nodeSimilarity = RelatedQuerySearch.conceptSimilarity(queryEdge.getSource(), // graphEdge.getSource()); // } else { // nodeSimilarity = RelatedQuerySearch.conceptSimilarity(queryEdge.getDestination(), // graphEdge.getDestination()); // } // If the found edge peudo-destination is similar to the query edge pseudo-destination // if (nodeSimilarity > RelatedQuerySearch.MIN_SIMILARITY) { // The destination if outgoing the source if isIncoming Long queryNextNode; MappedNode graphNextNode; if (isIncoming) { queryNextNode = queryEdge.getSource(); // graphNextNode = graphEdge.getSource(); graphNextNode = new MappedNode(graphEdge.getSource(), graphEdge, 0, isIncoming, false); } else { queryNextNode = queryEdge.getDestination(); // graphNextNode = graphEdge.getDestination(); graphNextNode = new MappedNode(graphEdge.getDestination(), graphEdge, 0, isIncoming, false); } // Is this node coeherent with the structure? if (edgeMatch(queryEdge, graphEdge, newRelatedQuery)) { // That's a good edge!! Add it to this related query newRelatedQuery.map(queryEdge, graphEdge); // Map also the node newRelatedQuery.map(queryNextNode, graphNextNode); // The query node that we are going to map // Does it have graphEdges that we don't have mapped? boolean needExpansion = false; Collection<Edge> pseudoOutgoingEdges = query.incomingEdgesOf(queryNextNode); Long queryPrevNode = null; if (pseudoOutgoingEdges.size() > 0) { for (Edge pseudoEdge : pseudoOutgoingEdges) { needExpansion = !newRelatedQuery.hasMapped(pseudoEdge) && !pseudoEdge.equals(queryEdge); queryPrevNode = pseudoEdge.getDestination().equals(queryNextNode) ? pseudoEdge.getSource() : pseudoEdge.getDestination(); needExpansion = needExpansion && !queryPrevNode.equals(queryNode); if (needExpansion) { break; } } } pseudoOutgoingEdges = query.outgoingEdgesOf(queryNextNode); if (!needExpansion && pseudoOutgoingEdges.size() > 0) { for (Edge pseudoEdge : pseudoOutgoingEdges) { needExpansion = !newRelatedQuery.hasMapped(pseudoEdge) && !pseudoEdge.equals(queryEdge); queryPrevNode = pseudoEdge.getDestination().equals(queryNextNode) ? pseudoEdge.getSource() : pseudoEdge.getDestination(); needExpansion = needExpansion && !queryPrevNode.equals(queryNode); if (needExpansion) { break; } } } // Lookout! We need to check the outgoing part, if we did not already if (needExpansion) { // Possible outgoing branches List<IsomorphicQuery> tmpRelatedQueries; // Go find them! // log("Go find mapping for: " + queryNextNode + " // " + graphNextNode); tmpRelatedQueries = createQueries(query, queryNextNode, graphNextNode, newRelatedQuery); // Did we find any? if (tmpRelatedQueries != null) { // Ok so we found some, they are all good to me // More possible related queries // They already contain the root for (IsomorphicQuery branch : tmpRelatedQueries) { // All these related queries have found in this edge their match newRelatedQueries.add(branch); } } // else { // This query didn't find in this edge its match // continue; // } } else { // log("Complete query " + relatedQuery); // this related query has found in this edge is map // newRelatedQuery.map(queryNextNode, graphNextNode); newRelatedQueries.add(newRelatedQuery); } } // else { // info("Edge does not match %s - for %s : %d", graphEdge.getId(), // FreebaseConstants.convertLongToMid(graphNode), graphNode); // } } } } // after this cycle we should have found some, how do we check? if (newRelatedQueries.isEmpty()) { return null; } else { // basically in the *new* list are the related queries still valid and growing relatedQueries = newRelatedQueries; } } return relatedQueries.size() > 0 ? relatedQueries : null; }