void CacheResultsTest::computeCLLRetrivingPerfor(int queryGraphId, std::vector<std::vector<CacheEmbeddingNode *>> * cachedLinkedLists, double * linkedListRetriTime) { AdjacenceListsGRAPH * queryGraph = &(*queryGraphVector)[queryGraphId]; comboVertexMapping = new CacheEmbeddingNode*[queryGraph->getComboGraph()->size()]; for (int i = 0; i < queryGraph->getComboGraph()->size(); i++) { comboVertexMapping[i] = NULL; } TimeUtility llTime; llTime.StartCounterMill(); CacheEmbeddingNode * comboVertexStarting = (*cachedLinkedLists)[queryGraphId][queryGraph->getDFSComboVertexOrder()->at(0)]; while (comboVertexStarting != NULL) { comboVertexMapping[queryGraph->getDFSComboVertexOrder()->at(0)] = comboVertexStarting; recursiveEnumLinkedLists(1, queryGraph); comboVertexStarting = comboVertexStarting->adj; } (*linkedListRetriTime) += llTime.GetCounterMill(); delete[] comboVertexMapping; }
void TurboIsoBoostedMQO::execute() { // we precompuete a matching order here. computeMatchingOrder(); if (jointNodeMatchingOrder.size() != jointGraph->jointNodes.size()) { /* * some joint node doesn't have any candidates */ return; } JointGraphNode & jointNode = jointGraph->jointNodes[jointNodeMatchingOrder[0].jointNodeId]; if (jointNode.parentId != -1) { AdjacenceListsGRAPH * parentGraph = NULL; // the starting node represents a parent graph if (jointNode.parentId < queryGraphVector->size()) { parentGraph = &(*queryGraphVector)[jointNode.parentId]; } else { parentGraph = &(*newlyGeneratedGraphVector)[jointNode.parentId - queryGraphVector->size()]; } /* * enumerate the embeddings from the cache */ CacheRetrieval * cacheRetrieval = new CacheRetrieval(dataGraph, resultCaches); std::vector<std::vector<CacheEmbeddingNode *>> candidates; cacheRetrieval->retrieveEmbeddingCandidate(queryGraph, parentGraph, &jointNode, &jointNodeMatchingOrder[0], embedding, &inverseEmbedding, &candidates); cout << "Start from Parent, candidate size: " << candidates.size() << endl << endl; for (std::vector<std::vector<CacheEmbeddingNode *>>::iterator candidateIter = candidates.begin(); candidateIter != candidates.end(); candidateIter++) { if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) { needReturn = true; return; } map<int, int> updatedQueryVertexMap; for (int comboNodeId = 0; comboNodeId < parentGraph->getComboGraph()->size(); comboNodeId++) { if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) { needReturn = true; return; } // each combo node corresponding to cache embedding node which contains multiple matched data vertices ComboNODE & comboNode = (*(parentGraph->getComboGraph()))[comboNodeId]; for (int comboVertexIter = 0; comboVertexIter < comboNode.queryVertices.size(); comboVertexIter++) { int dataVertexId = (*candidateIter)[comboNodeId]->comboMappingVertices[comboVertexIter]; int queryVertexId = jointNode.mapping[comboNode.queryVertices[comboVertexIter]]; if (embedding[queryVertexId] == -1) { updateState(queryVertexId, dataVertexId); updatedQueryVertexMap.insert(std::pair<int, int>(dataVertexId, queryVertexId)); } } } // next iteration resuriveSearch(1); // recover the last for (map<int, int>::iterator updatedVIter = updatedQueryVertexMap.begin(); updatedVIter != updatedQueryVertexMap.end(); updatedVIter++) { restoreState(updatedVIter->first, updatedVIter->second); } } delete cacheRetrieval; } else { // the starting node represents a stand alone vertex AdjacenceListsGRAPH::Vertex * queryVertex = queryGraph->getVertexAddressByVertexId(jointNode.mapping[0]); std::map<int, std::vector<int>>::iterator candidates = dataGraph->getLabelVertexList()->find(queryVertex->label); for (vector<int>::iterator candidateIter = candidates->second.begin(); candidateIter != candidates->second.end(); candidateIter++) { if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) { needReturn = true; return; } // start with each candidate if (degreeFilter(queryVertex->id, *candidateIter)) { updateState(queryVertex->id, *candidateIter); resuriveSearch(1); restoreState(queryVertex->id, *candidateIter); } } } }
/* * Given a PCM. we pre-compute a matching order here. * to use the exploration similar to turboIso. we can define a BFS order */ void TurboIsoBoostedMQO::computeMatchingOrder() { //build candidate size map vector<std::pair<int, int>> inverseMap; for (size_t nodeIndex = 0; nodeIndex < jointGraph->jointNodes.size(); nodeIndex++) { int parentId = jointGraph->jointNodes[nodeIndex].parentId; if (parentId != -1) { inverseMap.push_back(std::pair<int, int>((*numberOfEmbeddings)[parentId], nodeIndex)); } else { AdjacenceListsGRAPH::Vertex * queryVertex = queryGraph->getVertexAddressByVertexId(jointGraph->jointNodes[nodeIndex].mapping[0]); std::map<int, std::vector<int>>::iterator candidates = dataGraph->getLabelVertexList()->find(queryVertex->label); if (candidates != dataGraph->getLabelVertexList()->end()) { inverseMap.push_back(std::pair<int, int>(candidates->second.size(), nodeIndex)); } else { return; } } } std::sort(inverseMap.begin(), inverseMap.end()); // bfs order, start from the minimum size cache bool * flags = new bool[jointGraph->jointNodes.size()]; for (int i = 0; i < jointGraph->jointNodes.size(); i++) { flags[i] = false; } queue<int> visited; JointNodeOrderNode startNodeOrderNode; //@debug for (size_t i = 0; i < jointGraph->jointNodes.size(); i++) { if (jointGraph->jointNodes[i].parentId != -1) { visited.push(i); flags[i] = true; startNodeOrderNode.jointNodeId = i; break; } } /*jointNodeOrderNode.jointNodeId = inverseMap[0].second; visited.push(inverseMap[0].second); flags[inverseMap[0].second] = true;*/ jointNodeMatchingOrder.push_back(startNodeOrderNode); while (!visited.empty()) { int nodeId = visited.front(); visited.pop(); for (size_t nodeIndex = 0; nodeIndex < jointGraph->jointNodes.size(); nodeIndex++) { if (!flags[nodeIndex] && jointGraph->edge(nodeIndex, nodeId)) { flags[nodeIndex] = true; visited.push(nodeIndex); JointNodeOrderNode nextJointNodeOrderNode; nextJointNodeOrderNode.jointNodeId = nodeIndex; jointNodeMatchingOrder.push_back(nextJointNodeOrderNode); } } } delete[] flags; /* * add the common or connected already mapped query vertices */ for (int i = 0; i < jointNodeMatchingOrder.size(); i++) { JointNodeOrderNode & i_jointNodeOrderNode = jointNodeMatchingOrder[i]; JointGraphNode & i_jointGraphNode = jointGraph->jointNodes[i_jointNodeOrderNode.jointNodeId]; } /* * add the common or connected already mapped query vertices */ for (int i = 0; i < jointNodeMatchingOrder.size(); i++) { JointNodeOrderNode & i_jointNodeOrderNode = jointNodeMatchingOrder[i]; JointGraphNode & i_jointGraphNode = jointGraph->jointNodes[i_jointNodeOrderNode.jointNodeId]; /* * initialize it */ for (int mappingIdex = 0; mappingIdex < i_jointGraphNode.mapping.size(); mappingIdex++) { i_jointNodeOrderNode.preConnectedMappedVertex.push_back(vector<int>()); i_jointNodeOrderNode.preMultiCoveredVertex[mappingIdex] = -1; i_jointNodeOrderNode.uncoveredEdges.push_back(std::map<int, vector<int>>()); } for (int j = 0; j < i; j++) { JointNodeOrderNode & j_jointNodeOrderNode = jointNodeMatchingOrder[j]; JointGraphNode & j_jointGraphNode = jointGraph->jointNodes[j_jointNodeOrderNode.jointNodeId]; if (jointGraph->edge(i_jointNodeOrderNode.jointNodeId, j_jointNodeOrderNode.jointNodeId)) { // if these two joint node has edges for (int i_mappingIdex = 0; i_mappingIdex < i_jointGraphNode.mapping.size(); i_mappingIdex++) { // for each of the vertex within this joint node for (int j_mappingIdex = 0; j_mappingIdex < j_jointGraphNode.mapping.size(); j_mappingIdex++) { if (i_jointGraphNode.mapping[i_mappingIdex] == j_jointGraphNode.mapping[j_mappingIdex]) { // this two joint node covered a common query vertex i_jointNodeOrderNode.preMultiCoveredVertex[i_mappingIdex] = j_jointGraphNode.mapping[j_mappingIdex]; if (i_jointNodeOrderNode.preConnectedMappedVertex[i_mappingIdex].size() > 0) { i_jointNodeOrderNode.preConnectedMappedVertex[i_mappingIdex].swap(vector<int>()); } break; } else if (queryGraph->edge(i_jointGraphNode.mapping[i_mappingIdex], j_jointGraphNode.mapping[j_mappingIdex])) { i_jointNodeOrderNode.preConnectedMappedVertex[i_mappingIdex].push_back(j_jointGraphNode.mapping[j_mappingIdex]); } } } } } } /* * add uncovered query vertices */ for (int i = 0; i < jointNodeMatchingOrder.size(); i++) { JointNodeOrderNode & jointNodeOrderNode = jointNodeMatchingOrder[i]; JointGraphNode & jointGraphNode = jointGraph->jointNodes[jointNodeOrderNode.jointNodeId]; AdjacenceListsGRAPH * parentGraph = NULL; if (jointGraphNode.parentId >= queryGraphVector->size()) { parentGraph = &(*newlyGeneratedGraphVector)[jointGraphNode.parentId - queryGraphVector->size()]; } else { parentGraph = &(*queryGraphVector)[jointGraphNode.parentId]; } std::vector<ComboNODE> * comboGraph = parentGraph->getComboGraph(); for (int i_comboIndex = 0; i_comboIndex < comboGraph->size(); i_comboIndex++) { for (int j_comboIndex = i_comboIndex + 1; j_comboIndex < comboGraph->size(); j_comboIndex++) { for (std::vector<int>::iterator i_comboVerIter = (*comboGraph)[i_comboIndex].queryVertices.begin(); i_comboVerIter != (*comboGraph)[i_comboIndex].queryVertices.end(); i_comboVerIter++) { for (std::vector<int>::iterator j_comboVerIter = (*comboGraph)[j_comboIndex].queryVertices.begin(); j_comboVerIter != (*comboGraph)[j_comboIndex].queryVertices.end(); j_comboVerIter++) { if (!parentGraph->edge(*i_comboVerIter, *j_comboVerIter)) { if (queryGraph->edge(jointGraphNode.mapping[*i_comboVerIter], jointGraphNode.mapping[*j_comboVerIter])) { // this is a uncovered edge std::map<int, vector<int>>::iterator uncoverIter = jointNodeOrderNode.uncoveredEdges[*i_comboVerIter].find(j_comboIndex); if (uncoverIter == jointNodeOrderNode.uncoveredEdges[*i_comboVerIter].end()) { vector<int> uncoverConV; uncoverConV.push_back(jointGraphNode.mapping[*j_comboVerIter]); jointNodeOrderNode.uncoveredEdges[*i_comboVerIter].insert(std::pair<int, vector<int>>(*i_comboVerIter, uncoverConV)); } else { uncoverIter->second.push_back(jointGraphNode.mapping[*j_comboVerIter]); } } } } } } } } }
void TurboIsoBoostedMQO::resuriveSearch(int matchingOrderIndex) { if (recursiveCallsNo++ >= GlobalConstant::G_enoughRecursiveCalls) { (*numberOfEmbeddings)[queryGraph->graphId] = -1; needReturn = true; return; } if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) { needReturn = true; return; } if (matchingOrderIndex == jointNodeMatchingOrder.size()) { #ifdef DEBUG cout << "Find a Embedding for query " << queryGraph->graphId << "{"; for (int i = 0; i < queryGraph->getNumberOfVertexes(); i++) { cout << embedding[i] << " "; } cout << " } " << endl; #endif (*numberOfEmbeddings)[queryGraph->graphId] ++; // already reached to the last node. a full embedding was found if (needSaveCache) { ComboLinkedLists::addEmbeddingToCache(resultCaches, queryGraph, embedding); } } else { JointGraphNode & jointNode = jointGraph->jointNodes[jointNodeMatchingOrder[matchingOrderIndex].jointNodeId]; if (jointNode.parentId != -1) { /* * the next joint node represents a parent graph, we enumerate the candaite and for each candidate, we try to go to next iteration */ AdjacenceListsGRAPH * parentGraph = NULL; if (jointNode.parentId < queryGraphVector->size()) { parentGraph = &(*queryGraphVector)[jointNode.parentId]; } else { parentGraph = &(*newlyGeneratedGraphVector)[jointNode.parentId - queryGraphVector->size()]; } /* * enumerate the embeddings from the cache */ CacheRetrieval * cacheRetrieval = new CacheRetrieval(dataGraph, resultCaches); std::vector<std::vector<CacheEmbeddingNode *>> candidates; cacheRetrieval->retrieveEmbeddingCandidate(queryGraph, parentGraph, &jointNode, &jointNodeMatchingOrder[matchingOrderIndex], embedding, &inverseEmbedding, &candidates); for (std::vector<std::vector<CacheEmbeddingNode *>>::iterator candidateIter = candidates.begin(); candidateIter != candidates.end(); candidateIter++) { if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) { needReturn = true; return; } map<int, int> updatedQueryVertexMap; for (int comboNodeId = 0; comboNodeId < parentGraph->getComboGraph()->size(); comboNodeId++) { if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) { needReturn = true; return; } // each combo node corresponding to cache embedding node which contains multiple matched data vertices ComboNODE & comboNode = (*(parentGraph->getComboGraph()))[comboNodeId]; for (int comboVertexIter = 0; comboVertexIter < comboNode.queryVertices.size(); comboVertexIter++) { int dataVertexId = (*candidateIter)[comboNodeId]->comboMappingVertices[comboVertexIter]; int queryVertexId = jointNode.mapping[comboNode.queryVertices[comboVertexIter]]; if (embedding[queryVertexId] == -1) { updateState(queryVertexId, dataVertexId); updatedQueryVertexMap.insert(std::pair<int, int>(queryVertexId, dataVertexId)); } } } // next iteration resuriveSearch(matchingOrderIndex + 1); // recover the last for (map<int, int>::iterator updatedVIter = updatedQueryVertexMap.begin(); updatedVIter != updatedQueryVertexMap.end(); updatedVIter++) { restoreState(updatedVIter->first, updatedVIter->second); } } delete cacheRetrieval; } else { /* * the next node represents a stand alone query vertex. * stand alone query vertex cannot be matched before. so no need to ensure multi-map consistency */ AdjacenceListsGRAPH::Vertex * queryVertex = queryGraph->getVertexAddressByVertexId(jointNode.mapping[0]); JointGraphNode & parentJointNode = jointGraph->jointNodes[jointNodeMatchingOrder[matchingOrderIndex - 1].jointNodeId]; AdjacenceListsGRAPH::Vertex * parentMap = NULL; if (parentJointNode.parentId == -1) { // its parent is a stand alone vertex, we just get the mapped datavertex of its parent parentMap = dataGraph->getVertexAddressByVertexId(embedding[parentJointNode.mapping[0]]); } else { // its parent is a parent graph, we get a already mapped data vertex of a query vertex which is connected to this vertex for (size_t queryVertexIndex = 0; queryVertexIndex <= queryGraph->getNumberOfVertexes(); queryVertexIndex++) { if (embedding[queryVertexIndex] != -1 && queryGraph->edge(queryVertex->id, queryVertexIndex)) { parentMap = dataGraph->getVertexAddressByVertexId(embedding[queryVertexIndex]); break; } } } /* * we get is parent joint node, as its parent node has already been matched. we can use exploration to get the candidates */ std::map<int, std::vector<int>>::iterator exploreCandidates = parentMap->labelVertexList.find(queryVertex->label); if (exploreCandidates == parentMap->labelVertexList.end()) { // no candidate found return; } else { for (vector<int>::iterator candidateIter = exploreCandidates->second.begin(); candidateIter != exploreCandidates->second.end(); candidateIter++) { if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) { needReturn = true; return; } if (degreeFilter(queryVertex->id, *candidateIter) && isJoinable(queryVertex->id, *candidateIter)) { updateState(queryVertex->id, *candidateIter); resuriveSearch(matchingOrderIndex + 1); restoreState(queryVertex->id, *candidateIter); } } } } } }
/* * With the partial embeddings ready for this query graph, we are ready to process the joining process * The joining process is also a recursively enumeration process */ void RecurParEmbConstruct::recursiveComputePartialEmbedding(int matchedToOrderIndex, int selfJoinOrderIndex) { if ((*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS || (*numberOfEmbeddings)[queryGraph->graphId]==-1) { return; } /***************************************** * Terminate conditions * *****************************************/ if (mappedDataVertexSet.size() == queryGraph->getNumberOfVertexes()) { if (checkPartialEmbeddingUncoveredEdge()) { /* * We got a full embedding by only use the caches. Add it. */ (*numberOfEmbeddings)[queryGraph->graphId] ++; /* * We cache the results if and only if it has some children */ if ((*patternContainmentMap)[queryGraph->graphId].children.size() != 0) { cachedResultLists->addEmbeddingToCache(queryGraph, partialEmbedding); } } return; } if (matchedToOrderIndex == joiningOrder->size()) { /* * we iterate to the end of all its minimum query cover parents */ if (matchedToOrderIndex > 0 && mappedDataVertexSet.size() == 0) { /* * it has parents, however, we cannot get any partial embedding from its parent caches, that means, the query graph wouldn't have any embeddings */ return; } else { /* * @subgraph isomorphism. pass it * We only save the cache results if and only if this graph has pcm children */ if (checkPartialEmbeddingUncoveredEdge()) { // Call subgraph isomorphism algorithm runSubgraphIsomorphismSearch(); } return; } } /***************************************** * Set the parent graph in this round *****************************************/ int parentQueryGraphId = joiningOrder->at(matchedToOrderIndex); AdjacenceListsGRAPH * parentQueryGraph = NULL; if (parentQueryGraphId < queryGraphVector->size()) { parentQueryGraph = &(*queryGraphVector)[parentQueryGraphId]; } else { parentQueryGraph = &(*newlyGeneratedGraphVector)[parentQueryGraphId - queryGraphVector->size()]; } std::vector<int> * parentDFSComboVertexOrder = parentQueryGraph->getDFSComboVertexOrder(); std::vector<ComboNODE> * parentComboGraph = parentQueryGraph->getComboGraph(); /* * Find the mappings of this parent graph */ std::map<int, std::vector<std::vector<int>>>::iterator vertexMappingMapIterator = (*patternContainmentMap)[parentQueryGraphId].containmentRelationshipMappingLists.find(queryGraph->graphId); /* * The mapping from the parent graph to this graph: (0->? 1->? 2->?) */ std::vector<int> * vertexMappingList = &vertexMappingMapIterator->second[selfJoinOrderIndex]; std::vector<EmbeddingNode *> parentComboEmbedding; for (int i = 0; i<parentComboGraph->size(); i++) { parentComboEmbedding.push_back(NULL); } /***************************************** * Prepare for Next recursieve query round *****************************************/ if (selfJoinOrderIndex == vertexMappingMapIterator->second.size() - 1) { matchedToOrderIndex++; selfJoinOrderIndex = 0; } else { selfJoinOrderIndex++; } /***************************************** * enumerate and compose the cached embeddings *****************************************/ EmbeddingNode * rootsMatchedVertices = (*comboLinkedLists)[parentQueryGraphId][0]; int * updatedVertexId = new int[5]; for (int i = 0; i<5; i++) { updatedVertexId[i] = -1; } while (rootsMatchedVertices != NULL) { if ((*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS || (*numberOfEmbeddings)[queryGraph->graphId]==-1) { return; } //1. Make sure no data vertices can be used multiple times AND the same data vertex to each query vertex bool isJoinable = true; for (int i = 0; i<(*parentComboGraph)[0].queryVertices.size(); i++) { int mappedQueryVertex = (*vertexMappingList)[(*parentComboGraph)[0].queryVertices[i]]; if (partialEmbedding[mappedQueryVertex] != -1) { // same data vertex to each query vertex if (partialEmbedding[mappedQueryVertex] != rootsMatchedVertices->comboMappingVertices[i]) { isJoinable = false; break; } } else { if (mappedDataVertexSet.find(rootsMatchedVertices->comboMappingVertices[i]) == mappedDataVertexSet.end()) { // no data vertices can be used multiple times partialEmbedding[mappedQueryVertex] = rootsMatchedVertices->comboMappingVertices[i]; mappedDataVertexSet.insert(rootsMatchedVertices->comboMappingVertices[i]); updatedVertexId[i] = mappedQueryVertex; } else { isJoinable = false; break; } } } if (isJoinable) { //2. start iteratiing inner embeddings parentComboEmbedding[(*parentDFSComboVertexOrder)[0]] = rootsMatchedVertices; enumberateEmbeddingLinkedList(1, matchedToOrderIndex, selfJoinOrderIndex, parentComboGraph, parentDFSComboVertexOrder, vertexMappingList, &parentComboEmbedding); } //3. restore to initial status for (int i = 0; i<5; i++) { if (updatedVertexId[i] != -1) { mappedDataVertexSet.erase(partialEmbedding[updatedVertexId[i]]); partialEmbedding[updatedVertexId[i]] = -1; updatedVertexId[i] = -1; } } //4. next root trial rootsMatchedVertices = rootsMatchedVertices->adj; } //5. release memory delete[] updatedVertexId; }
void TurboIsoMQO::resuriveSearch(int matchingOrderIndex) { if (recursiveCallsNo++ >= GlobalConstant::G_enoughRecursiveCalls) { (*numberOfEmbeddings)[queryGraph->graphId] = -1; needReturn = true; return; } if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) { needReturn = true; return; } if (matchingOrderIndex == jointNodeMatchingOrder.size()) { #ifdef DEBUG cout << "Find a Embedding for query " << queryGraph->graphId << "{"; for (int i = 0; i < queryGraph->getNumberOfVertexes(); i++) { cout << embedding[i] << " "; } cout << " } " << endl; #endif (*numberOfEmbeddings)[queryGraph->graphId] ++; // already reached to the last node. a full embedding was found if (needSaveCache) { ComboLinkedLists::addEmbeddingToCache(resultCaches, queryGraph, embedding); } } else { JointGraphNode & jointNode = jointGraph->jointNodes[jointNodeMatchingOrder[matchingOrderIndex].jointNodeId]; if (jointNode.parentId != -1) { /* * the next joint node represents a parent graph, we enumerate the candaite and for each candidate, we try to go to next iteration */ AdjacenceListsGRAPH * parentGraph = NULL; if (jointNode.parentId < queryGraphVector->size()) { parentGraph = &(*queryGraphVector)[jointNode.parentId]; } else { parentGraph = &(*newlyGeneratedGraphVector)[jointNode.parentId - queryGraphVector->size()]; } /* * enumerate the embeddings from the cache */ CacheRetrieval * cacheRetrieval = new CacheRetrieval(dataGraph, resultCaches); std::vector<std::vector<CacheEmbeddingNode *>> candidates; cacheRetrieval->retrieveEmbeddingCandidate(queryGraph, parentGraph, &jointNode, &jointNodeMatchingOrder[matchingOrderIndex], embedding, &inverseEmbedding, &candidates); cout << "Candidate Size: " << candidates.size() << endl; /* * will be updated query vertex */ vector<int> updatingQueryVertex; for (int comboNodeId = 0; comboNodeId < parentGraph->getComboGraph()->size(); comboNodeId++) { ComboNODE & comboNode = (*(parentGraph->getComboGraph()))[comboNodeId]; for (int comboVertexIter = 0; comboVertexIter < comboNode.queryVertices.size(); comboVertexIter++) { int queryVertexId = jointNode.mapping[comboNode.queryVertices[comboVertexIter]]; if (embedding[queryVertexId] == -1) { updatingQueryVertex.push_back(queryVertexId); } } } for (std::vector<std::vector<CacheEmbeddingNode *>>::iterator candidateIter = candidates.begin(); candidateIter != candidates.end(); candidateIter++) { if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) { needReturn = true; return; } for (int comboNodeId = 0; comboNodeId < parentGraph->getComboGraph()->size(); comboNodeId++) { // each combo node corresponding to cache embedding node which contains multiple matched data vertices ComboNODE & comboNode = (*(parentGraph->getComboGraph()))[comboNodeId]; for (int comboVertexIter = 0; comboVertexIter < comboNode.queryVertices.size(); comboVertexIter++) { int dataVertexId = (*candidateIter)[comboNodeId]->comboMappingVertices[comboVertexIter]; int queryVertexId = jointNode.mapping[comboNode.queryVertices[comboVertexIter]]; if (embedding[queryVertexId] == -1) { updateState(queryVertexId, dataVertexId); } } } // next iteration resuriveSearch(matchingOrderIndex + 1); // recover the last for (vector<int>::iterator updatedVIter = updatingQueryVertex.begin(); updatedVIter != updatingQueryVertex.end(); updatedVIter++) { restoreState(*updatedVIter); } } delete cacheRetrieval; } else { /* * the next node represents a stand alone query vertex. * stand alone query vertex cannot be matched before. so no need to ensure multi-map consistency */ AdjacenceListsGRAPH::Vertex * queryVertex = queryGraph->getVertexAddressByVertexId(jointNode.mapping[0]); std::vector<int> * candidates = NULL; if (matchingOrderIndex == 0) { // the starting vertex cannot use exploration std::map<int, std::vector<int>>::iterator candidateIter = dataGraph->getLabelVertexList()->find(queryVertex->label); if (candidateIter == dataGraph->getLabelVertexList()->end()) { return; } candidates = &candidateIter->second; } else { /* * the following vertex use candidate exploration from its mapped parents. * we explore a connected, already mapped query vertex which generate minimum number of candidates. */ int minCandidateSize = INT_MAX; for (size_t queryVertexIndex = 0; queryVertexIndex <= queryGraph->getNumberOfVertexes(); queryVertexIndex++) { if (embedding[queryVertexIndex] != -1 && queryGraph->edge(queryVertex->id, queryVertexIndex)) { AdjacenceListsGRAPH::Vertex * alreadyMappedDataVer = dataGraph->getVertexAddressByVertexId(embedding[queryVertexIndex]); std::map<int, std::vector<int>>::iterator candidateIter = alreadyMappedDataVer->labelVertexList.find(queryVertex->label); if (candidateIter == alreadyMappedDataVer->labelVertexList.end()) { return; } else { if (candidateIter->second.size() < minCandidateSize) { minCandidateSize = candidateIter->second.size(); candidates = &candidateIter->second; } } } } } /* * for each of the candidates, we further iterate */ for (vector<int>::iterator candidateIter = candidates->begin(); candidateIter != candidates->end(); candidateIter++) { if (needReturn || (*numberOfEmbeddings)[queryGraph->graphId] >= GlobalConstant::G_SUFFICIENT_NUMBER_EMBEDDINGS) { needReturn = true; return; } if (degreeFilter(queryVertex->id, *candidateIter) && isJoinable(queryVertex->id, *candidateIter)) { updateState(queryVertex->id, *candidateIter); resuriveSearch(matchingOrderIndex + 1); restoreState(queryVertex->id); } } } } }