/* * CoreCover.java * ------------- * Implements our CoreCover algorithm. * $Id: CoreCover.java,v 1.25 2000/11/28 00:48:08 chenli Exp $ */ import java.util.*; class CoreCover { public static int numVTs = 0; public static long groupedNumVTs = 0; // grouped view tuples public static int numMR = 0; public static int numGMR = 0; public static int sizeGMR = 0; public static long timeMR = 0; public static long timeFirstGMR = 0; // time when the 1st GMR is generated public static long timeAllGMR = 0; // time when all GMRs are generated static long startTime = 0; static long endTime = 0; // calls our CoreCover algorithm to generate rewritings static HashSet genPlan(Query query, Vector views) { numVTs = 0; numMR = 0; numGMR = 0; sizeGMR = 0; timeMR = 0; timeFirstGMR = 0; timeAllGMR = 0; startTime = 0; endTime = 0; startTime = System.currentTimeMillis(); // minimize the query query = query.minimize(); // construct the canonical db Database canDb = constructCanonicalDB(query); UserLib.myprintln("canDb = " + canDb.toString()); // compute view tuples HashSet viewTuples = computeViewTuples(canDb, views); // compute tuple-cores computeTupleCores(viewTuples, query); // group view tuples according to their tuple-cores numVTs = computeNumVTs(viewTuples); viewTuples = groupViewTuples(viewTuples); groupedNumVTs = viewTuples.size(); UserLib.myprintln("There are ***" + numVTs + "*** compressed view tuples = " + viewTuples); int newNum = viewTuples.size(); //System.out.println("oldTupleNum = " + oldNum + " newTupleNum = " + newNum); UserLib.myprintln("viewTuples = " + viewTuples); // use tuple-cores to cover query subgoals HashSet rewritings = coverQuerySubgoals(viewTuples, query); UserLib.myprintln("rewritings = " + rewritings); if (!rewritings.isEmpty()) { // only count non-empty rewritings endTime = System.currentTimeMillis(); timeMR = endTime - startTime; } return rewritings; } /** * constructs a canonical database of a query */ static Database constructCanonicalDB(Query query) { HashSet tuples = new HashSet(); for (Iterator iter = query.getBody().iterator(); iter.hasNext();) { Subgoal subgoal = (Subgoal) iter.next(); Tuple tuple = new Tuple(subgoal); tuples.add(tuple); // we treat each subgoal as a "tuple" } return new Database(tuples); } /** * given a canonical db and a set of views, computes the view tuples */ static HashSet computeViewTuples(Database canDb, Vector views) { HashSet viewTuples = new HashSet(); for (int i = 0; i < views.size(); i ++) { Query view = (Query) views.elementAt(i); Relation rel = canDb.execQuery(view); viewTuples.addAll(rel.getTuples()); // add them to the results } return viewTuples; } /** * computes the tuple cores of all view tuples. */ static void computeTupleCores(HashSet viewTuples, Query query) { for (Iterator iter = viewTuples.iterator(); iter.hasNext();) { Tuple viewTuple = (Tuple) iter.next(); computeTupleCore(viewTuple, query); } } /** * Computes the tuple core of a vew tuple, assuming the query is minimal. * find a maximum subset G of query subgoals such that there is a set * H of subgoals in t^exp, such that there is a mapping \mu from G to * H ,and the mapping has the three properties */ static void computeTupleCore(Tuple viewTuple, Query query) { // view-tuple expansion Mapping phi = viewTuple.getMapping(); Query view = viewTuple.getQuery(); Query viewExp = phi.apply(view); Vector viewSubgoals = viewExp.getBody(); HashSet vSubgoalSubsets = UserLib.genSubsets(viewSubgoals); // query subgoals Vector querySubgoals = query.getBody(); HashSet qSubgoalSubsets = UserLib.genSubsets(querySubgoals); int upperBound = querySubgoals.size(); if (upperBound > viewSubgoals.size()) upperBound = viewSubgoals.size(); // scans the subsets from the largests one to the smallest one for (int size = upperBound; size >= 1; size --) { for (Iterator iter = qSubgoalSubsets.iterator(); iter.hasNext();) { // for this "i"^th around, we consider only subsets with size i HashSet qSubgoalSubset = (HashSet) iter.next(); if (qSubgoalSubset.size() != size) continue; if (findCore(qSubgoalSubset, query, viewTuple, viewExp, vSubgoalSubsets)) { UserLib.myprintln("!!!!Find a core: " + qSubgoalSubset); viewTuple.setCore(qSubgoalSubset); return; } } } // empty core viewTuple.setCore(new HashSet()); } /** * Given a set of query subgoals, a view tuple, and all subsets of the * subgoals in the tuple's expansion, checks if there is a mapping from * this query-subgoal subset to a view subgoal subset such that the * mapping has the "three properties." */ static boolean findCore(HashSet qSubgoalSubset, Query query, Tuple viewTuple, Query viewExp, HashSet vSubgoalSubsets) { // change the set to a sequence Vector qSubgoalSeq = new Vector(qSubgoalSubset); for (Iterator iter1 = vSubgoalSubsets.iterator(); iter1.hasNext();) { HashSet vSubgoalSubset = (HashSet) iter1.next(); if (vSubgoalSubset.size() != qSubgoalSubset.size()) continue; HashSet vSubgoalsPermus = UserLib.genPermutations(vSubgoalSubset); for (Iterator iter2 = vSubgoalsPermus.iterator(); iter2.hasNext();) { Vector vSubgoalSeq = (Vector) iter2.next(); if (testCoreMapping(qSubgoalSeq, query, vSubgoalSeq, viewExp)) return true; // found it! } } return false; } /** * Given a sequence of query subgoals and a sequence of view subgoals, * tests whether there is a mapping from the former to the latter that * satisifies the three properties in the definition of tuple-core. */ static boolean testCoreMapping(Vector qSubgoalSeq, Query query, Vector vSubgoalSeq, Query viewExp) { if (qSubgoalSeq.size() != vSubgoalSeq.size()) UserLib.myerror("CoreCover.testCoreMapping(): wrong sequences"); HashMap mu = new HashMap(); for (int i = 0; i < qSubgoalSeq.size(); i ++) { Subgoal querySubgoal = (Subgoal) qSubgoalSeq.elementAt(i); Subgoal viewSubgoal = (Subgoal) vSubgoalSeq.elementAt(i); if (!querySubgoal.isSameName(viewSubgoal)) return false; Vector queryArgs = querySubgoal.getArgs(); Vector viewArgs = viewSubgoal.getArgs(); if (queryArgs.size() != viewArgs.size()) UserLib.myerror("CoreCover.testCoreMapping(), wrong args!"); // checks if a query arg is unifiable with the corresponding view arg for (int j = 0; j < queryArgs.size(); j ++) { Argument queryArg = (Argument) queryArgs.elementAt(j); Argument viewArg = (Argument) viewArgs.elementAt(j); if (queryArg.isConst()) { if (!viewArg.isConst()) // constant -> same constant return false; if (!queryArg.equals(viewArg)) return false; continue; } // queryArg is a var if (viewExp.isDistVar(viewArg)) { if (!queryArg.equals(viewArg)) // View D vars, identity return false; continue; } // viewArg is ND if (query.isDistVar(queryArg)) // NOT D (query) -> ND (view) return false; // queryArg = ND, and viewArg = ND if (checkProperty2(queryArg, qSubgoalSeq, query)) return false; // remember the 1-to-1 mapping Argument image = (Argument) mu.get(queryArg); if (image == null) mu.put(queryArg, viewArg); else { if (!image.equals(viewArg)) // one-to-one return false; } } } return true; } /** * checks the second property of the mapping. i.e., tests if all the * subgoals in the query that use a given queryArg appear in qSubgoalSeq. */ static boolean checkProperty2(Argument queryArg, Vector qSubgoalSeq, Query query) { Vector body = query.getBody(); //UserLib.myprintln("body = " + body); for (int i = 0; i < body.size(); i ++) { Subgoal subgoal = (Subgoal) body.elementAt(i); Vector args = subgoal.getArgs(); if (args.contains(queryArg) && !qSubgoalSeq.contains(subgoal)) return false; } return true; } /** * Computes the tuple core of a vew tuple, assuming both the query and * the view are minimal already. * TODO: what if they are NOT minimal. */ static void computeTupleCore_OLD(Tuple viewTuple, Query query) { Query view = viewTuple.getQuery(); // sets core to the target query subgoals under the mapping HashSet core = viewTuple.getTargetSubgoals(); UserLib.myprintln("before shrinking: core = " + core); // shrinking core Mapping phi = viewTuple.getMapping(); HashMap reversedMap = new HashMap(); // scans the args in phi Set entrySet = phi.getMap().entrySet(); for (Iterator iter = entrySet.iterator(); iter.hasNext();) { Map.Entry mapEntry = (Map.Entry) iter.next(); Argument viewArg = (Argument) mapEntry.getKey(); Argument queryArg = (Argument) mapEntry.getValue(); if (removeable(core, phi, reversedMap, view, viewArg, query, queryArg)) { // finds a conflict, remove all query subgoals that use this arg core = removeConflictSubgoals(core, queryArg); } else { reversedMap.put(queryArg, viewArg); // reverses the mapping } } UserLib.myprintln("Final core = " + core); viewTuple.setCore(core); } /* * checks if some subgoals should be removed from a core */ static boolean removeable(HashSet core, Mapping phi, HashMap reversedMap, Query view, Argument viewArg, Query query, Argument queryArg) { // Removes subgoals if one of the following conditions is satisfied: Argument otherViewArg = (Argument) reversedMap.get(queryArg); if (otherViewArg != null && !otherViewArg.equals(viewArg)) { // we have a different view arg mapped to this query arg Argument image = null; if (view.isDistVar(otherViewArg)) image = phi.apply(otherViewArg); // ????? else image = otherViewArg; if (image == null) UserLib.myerror("CoreCover.removeable(): image is missing, 1."); if (!image.equals(queryArg)) // they should have the same image return true; } // 1. viewArg = "D", not removed if (view.isDistVar(viewArg)) return false; // 2. viewArg = "ND" and queryArg = "D" if (query.isDistVar(queryArg)) { //System.out.println("case 2: queryArg = D, viewArg = ND"); return true; } // 3. both are "ND", and some query subgoals that use this query arg // are not in the core Vector body = query.getBody(); for (int i = 0; i < body.size(); i ++) { Subgoal subgoal = (Subgoal) body.elementAt(i); if (subgoal.getArgs().contains(queryArg) && !core.contains(subgoal)) return true; } // 1. two variables in the view are mapped to // the same variable Y in the query, then remove all query // subgoals that use this variable Y /*Argument otherViewArg = (Argument) reversedMap.get(queryArg); if (otherViewArg != null && !otherViewArg.equals(viewArg)) { Argument image = null; if (view.isDist(otherViewArg)) image = phi.get(otherViewArg); // ????? else image = otherViewArg; if (image == null) UserLib.myerror("CoreCover.removeable(): image is missing, 1."); if (!image.equals(queryArg)) // they should have the same image return true; }*/ return false; } /** * removes the subgoals that use a query arg from a core */ static HashSet removeConflictSubgoals(HashSet core, Argument queryArg) { HashSet result = new HashSet(); for (Iterator iter = core.iterator(); iter.hasNext();) { Subgoal subgoal = (Subgoal) iter.next(); // checks if this subgoal uses this query arg if (!subgoal.getArgs().contains(queryArg)) result.add(subgoal); else { UserLib.myprintln("Remove subgoal " + subgoal); } } return result; } static HashSet coverQuerySubgoals(HashSet viewTuples, Query query) { HashSet rewritings = new HashSet(); // considers all the subsets in the descending order //HashSet tupleSubsets = UserLib.genSubsets(viewTuples); //UserLib.myprintln("after UserLib.genSubsets()"); sizeGMR = 0; numMR = 0; numGMR = 0; int upperBound = viewTuples.size(); if (upperBound >= query.getSubgoalNum()) // according to LMSS95 upperBound = query.getSubgoalNum(); // if the union of the tuple-cores doesn't cover all query subgoals, // just return no rewriting if (!unionCoverSubgoals(viewTuples, query)) return rewritings; // scans the subsets from the smallest one to the largest one boolean found = false; for (int size = 1; (size <= upperBound) && !found; size ++) { // considers subsets with the current size //System.out.println("# of view tuples = " + viewTuples.size() + //" size = " + size); HashSet tupleSubsets = UserLib.genSubsets(viewTuples, size); //System.out.println("# of tupleSubsets = " + tupleSubsets.size()); for (Iterator iter = tupleSubsets.iterator(); iter.hasNext();) { // for this "i"^th around, we consider only subsets with size i HashSet tupleSubset = (HashSet) iter.next(); if (tupleSubset.size() != size) UserLib.myerror("CoreCover.coverQuerySubgoals(), error!"); if (unionCoverSubgoals(tupleSubset, query)) {// found one rewritings.add(new Rewriting(tupleSubset, query)); sizeGMR = size; numGMR ++; numMR ++; /*System.out.println("\n tupleSubset " + tupleSubset + " query = " + query + "\n");*/ // time when the 1st GMR is generated if (!found) { endTime = System.currentTimeMillis(); timeFirstGMR = endTime - startTime; } found = true; } } if (found) { endTime = System.currentTimeMillis(); timeAllGMR = endTime - startTime; } } return rewritings; } // checks if the union of tuple cores covers all query subgoals static boolean unionCoverSubgoals(HashSet tupleSubset, Query query) { HashSet coreUnion = new HashSet(); for (Iterator iter2 = tupleSubset.iterator(); iter2.hasNext();) { Tuple viewTuple = (Tuple) iter2.next(); HashSet core = viewTuple.getCore(); coreUnion.addAll(core); } return coreUnion.containsAll(query.getBody()); } /** * Checks if a rewriting has a used a subset of view tuples in tupleSubset. */ static boolean containsTupleSubset(HashSet rewritings, HashSet tupleSubset) { for (Iterator iter = rewritings.iterator(); iter.hasNext();) { Rewriting rewriting = (Rewriting) iter.next(); HashSet viewTuples = rewriting.getViewTuples(); if (tupleSubset.containsAll(viewTuples)) return true; } return false; } /** * groups different views into equivalence classes */ static HashSet groupViewTuples(HashSet viewTuples) { HashSet groups = new HashSet(); for (Iterator iter = viewTuples.iterator(); iter.hasNext();) { Tuple viewTuple = (Tuple) iter.next(); // search for view tuples with the same utple-core boolean found = false; for (Iterator iter2 = groups.iterator(); iter2.hasNext();) { Tuple group = (Tuple) iter2.next(); if ((group != viewTuple) && group.sameCore(viewTuple)) { found = true; group.addEquTuple(viewTuple); break; } } if (!found) { // new equivalence class viewTuple.setEquSelf(); groups.add(viewTuple); } } return groups; } // computes the number of view tuples by considering the equivalence // view classes: computes the total. static int computeNumVTs(HashSet viewTuples) { int num = 0; for (Iterator iter = viewTuples.iterator(); iter.hasNext();) { Tuple tuple = (Tuple) iter.next(); num += tuple.getQuery().getCount(); } return num; } }