-
Notifications
You must be signed in to change notification settings - Fork 1
/
CoreCover.java
524 lines (432 loc) · 15.8 KB
/
CoreCover.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
/*
* 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;
}
}