/** * @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; }
@Override public List<RelatedQuery> call() throws Exception { IsomorphicQuery relatedQuery; List<IsomorphicQuery> relatedQueriesPartial = new LinkedList<>(); Set<RelatedQuery> relatedQueries = new HashSet<>(); // searchCount = 0; boolean warned = false; watch.start(); int i = 0; this.isQuit = false; while (graphNodes.hasNext()) { // System.out.println("Thread " + threadNumber + " Finshed " + ((double)i / chunkSize) // * 100 + "%"); MappedNode node = graphNodes.next(); // System.out.println("Processing node " + node.getNodeID()); // System.out.println(node); i++; try { relatedQuery = new IsomorphicQuery(query); // Map the first node relatedQuery.map(queryConcept, node); relatedQueriesPartial = createQueries(query, queryConcept, node, relatedQuery); // System.out.println(Utilities.searchCount); if (this.isQuit) { break; } if (relatedQueriesPartial != null) { if (skipSave) { continue; } IsomorphicQuerySearch.answerCount += relatedQueriesPartial.size(); relatedQueries.addAll(relatedQueriesPartial); // for (RelatedQuery rq : relatedQueries){ // System.out.println(rq); // } if (watch.getElapsedTimeMillis() > WARN_TIME || IsomorphicQuerySearch.answerCount > MAX_RELATED) { // warn("More than " + MAX_RELATED + " partial isomorphic // results"); warned = true; if (limitComputation) { // warn("Computation interrupted after " + // IsomorphicQuerySearch.answerCount + " partial isomorphic results"); break; } // IsomorphicQuerySearch.answerCount = 0; relatedQueriesPartial.clear(); IsomorphicQuerySearch.isBad = true; } // if ((!warned && watch.getElapsedTimeMillis() > WARN_TIME && // IsomorphicQuerySearch.answerCount > MAX_RELATED)) { // warn("More than " + MAX_RELATED + " partial isomorphic // results"); // warned = true; // if (limitComputation) { // warn("Computation interrupted after " + // IsomorphicQuerySearch.answerCount + " partial isomorphic results"); // break; // } // IsomorphicQuerySearch.isBad = true; // } } // System.out.println(Utilities.searchCount); } catch (OutOfMemoryError E) { if (relatedQueriesPartial != null) { relatedQueriesPartial.clear(); } IsomorphicQuerySearch.isBad = true; error("Memory exausted, so we are returning something but not everything."); System.gc(); return new LinkedList<>(); } // if (watch.getElapsedTimeMillis() > WARN_TIME) { // info("Computation %d [%d] took %d ms", threadNumber, Thread.currentThread().getId(), // watch.getElapsedTimeMillis()); // } } watch.stop(); // System.out.println("search count:" + this.searchCount); // System.out.println(this + "future finished"); return new LinkedList<>(relatedQueries); }
/** * 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; }