/** * Advance the internal document iterator to the specified document, or beyond if it doesn't. * * @param docid An internal document id. */ public void docIteratorAdvanceTo(int docid) { for (Qry q_i : this.args) { q_i.docIteratorAdvanceTo(docid); } this.docIteratorClearMatchCache(); }
/** * An instantiation of docIteratorHasMatch that is true if the query has a document that matches * the first query argument; some subclasses may choose to use this implementation. * * @param r The retrieval model that determines what is a match * @return True if the query matches, otherwise false. */ protected boolean docIteratorHasMatchFirst(RetrievalModel r) { Qry q_0 = this.args.get(0); if (q_0.docIteratorHasMatch(r)) { int docid = q_0.docIteratorGetMatch(); this.docIteratorSetMatchCache(docid); return true; } else { return false; } }
/** * An instantiation of docIteratorHasMatch that is true if the query has a document that matches * all query arguments; some subclasses may choose to use this implementation. * * @param r The retrieval model that determines what is a match * @return True if the query matches, otherwise false. */ protected boolean docIteratorHasMatchAll(RetrievalModel r) { boolean matchFound = false; // Keep trying until a match is found or no match is possible. while (!matchFound) { // Get the docid of the first query argument. Qry q_0 = this.args.get(0); if (!q_0.docIteratorHasMatch(r)) { return false; } int docid_0 = q_0.docIteratorGetMatch(); // Other query arguments must match the docid of the first query // argument. matchFound = true; for (int i = 1; i < this.args.size(); i++) { Qry q_i = this.args.get(i); q_i.docIteratorAdvanceTo(docid_0); if (!q_i.docIteratorHasMatch(r)) { // If any argument is exhausted return false; // there are no more matches. } int docid_i = q_i.docIteratorGetMatch(); if (docid_0 != docid_i) { // docid_0 can't match. Try again. q_0.docIteratorAdvanceTo(docid_i); matchFound = false; break; } } if (matchFound) { docIteratorSetMatchCache(docid_0); } } return true; }
/** * An instantiation of docIteratorHasMatch that is true if the query has a document that matches * at least one query argument; the match is the smallest docid to match; some subclasses may * choose to use this implementation. * * @param r The retrieval model that determines what is a match * @return True if the query matches, otherwise false. */ protected boolean docIteratorHasMatchMin(RetrievalModel r) { int minDocid = Qry.INVALID_DOCID; for (int i = 0; i < this.args.size(); i++) { Qry q_i = this.args.get(i); if (q_i.docIteratorHasMatch(r)) { int q_iDocid = q_i.docIteratorGetMatch(); if ((minDocid > q_iDocid) || (minDocid == Qry.INVALID_DOCID)) { minDocid = q_iDocid; } } } if (minDocid != Qry.INVALID_DOCID) { docIteratorSetMatchCache(minDocid); return true; } else { return false; } }
/** * Append an argument to the list of query operator arguments. * * @param q The query argument (query operator) to append. * @throws IllegalArgumentException q is an invalid argument */ public void appendArg(Qry q) throws IllegalArgumentException { // The query parser and query operator type system are too simple // to detect some kinds of query syntax errors. appendArg does // additional syntax checking while creating the query tree. It // also inserts SCORE operators between QrySop operators and QryIop // arguments, and propagates field information from QryIop // children to parents. Basically, it creates a well-formed // query tree. if (this instanceof QryIopTerm) { throw new IllegalArgumentException("The TERM operator has no arguments."); } // SCORE operators can have only a single argument of type QryIop. if (this instanceof QrySopScore) { if (this.args.size() > 0) { throw new IllegalArgumentException("Score operators can have only one argument"); } else if (!(q instanceof QryIop)) { throw new IllegalArgumentException( "The argument to a SCORE operator must be of type QryIop."); } else { this.args.add(q); return; } } // Check whether it is necessary to insert an implied SCORE // operator between a QrySop operator and a QryIop argument. if ((this instanceof QrySop) && (q instanceof QryIop)) { Qry impliedOp = new QrySopScore(); impliedOp.setDisplayName("#SCORE"); impliedOp.appendArg(q); this.args.add(impliedOp); return; } // QryIop operators must have QryIop arguments in the same field. if ((this instanceof QryIop) && (q instanceof QryIop)) { if (this.args.size() == 0) { ((QryIop) this).field = new String(((QryIop) q).getField()); } else { if (!((QryIop) this).field.equals(((QryIop) q).getField())) { throw new IllegalArgumentException( "Arguments to QryIop operators must be in the same field."); } } this.args.add(q); return; } // QrySop operators and their arguments must be of the same type. if ((this instanceof QrySop) && (q instanceof QrySop)) { this.args.add(q); return; } throw new IllegalArgumentException( "Objects of type " + q.getClass().getName() + " cannot be an argument to a query operator of type " + this.getClass().getName()); }
@Override protected void evaluate() throws IOException { this.invertedList = new InvList(this.getField()); // no argument if (args.size() == 0) return; if (args.size() == 1) { this.invertedList = ((QryIop) this.args.get(0)).invertedList; return; } // iterate each doc, greedy algorithms while (true) { // init doc_id int doc_id = Qry.INVALID_DOCID; if (this.docIteratorHasMatchAll(null)) doc_id = this.args.get(0).docIteratorGetMatch(); // fail to find a match all if (doc_id == Qry.INVALID_DOCID) break; // the last argument's position in doc List<Integer> positions = new ArrayList<Integer>(); // iterate each location while (true) { boolean success = false; int position = 0; // index from 1 to n-1 for (int i = 1; i < this.args.size(); i++) { // get previous pos if (!((QryIop) this.args.get(i - 1)).locIteratorHasMatch()) break; int position1 = ((QryIop) this.args.get(i - 1)).locIteratorGetMatch(); // go beyond pre pos ((QryIop) this.args.get(i)).locIteratorAdvancePast(position1); if (!((QryIop) this.args.get(i)).locIteratorHasMatch()) break; int position2 = ((QryIop) this.args.get(i)).locIteratorGetMatch(); // near condition satisfied? if (position2 > position1 && position2 - position1 <= this.dist) { position = position2; if (i == this.args.size() - 1) success = true; } else { success = false; break; } } // find a legal position if (success) { positions.add(position); // move each loc pointer for (Qry q_i : this.args) { ((QryIop) q_i).locIteratorAdvance(); } } else { // move first arg ((QryIop) this.args.get(0)).locIteratorAdvance(); // if no more match position for the first arg if (!((QryIop) this.args.get(0)).locIteratorHasMatch()) break; // reset other pointers to beginning for (int i = 1; i < this.args.size(); i++) { ((QryIop) this.args.get(i)).locIteratorReset(); int preposition = ((QryIop) this.args.get(0)).locIteratorGetMatch(); ((QryIop) this.args.get(i)).locIteratorAdvancePast(preposition); } } } // move doc pointer for (Qry q_i : this.args) q_i.docIteratorAdvancePast(doc_id); // success if (positions.size() > 0) this.invertedList.appendPosting(doc_id, positions); } }