/** * This helper method handles the case when a tuple is being removed from the table, before the * row has actually been removed from the table. All indexes on the table are updated to remove * the row. * * @param tblFileInfo details of the table being updated * @param ptup the tuple about to be removed from the table */ private void removeRowFromIndexes(TableInfo tblFileInfo, PageTuple ptup) { logger.debug( "Removing tuple " + ptup + " from indexes for table " + tblFileInfo.getTableName()); // Iterate over the indexes in the table. TableSchema schema = tblFileInfo.getSchema(); for (ColumnRefs indexDef : schema.getIndexes().values()) { TupleLiteral idxTup = IndexUtils.makeSearchKeyValue(indexDef, ptup, /* findExactTuple */ true); logger.debug("Removing tuple " + idxTup + " from index " + indexDef.getIndexName()); try { IndexInfo indexInfo = indexManager.openIndex(tblFileInfo, indexDef.getIndexName()); TupleFile tupleFile = indexInfo.getTupleFile(); PageTuple idxPageTup = IndexUtils.findTupleInIndex(idxTup, tupleFile); if (idxPageTup == null) { throw new IllegalStateException( "Can't find tuple in " + "index corresponding to table's tuple."); } tupleFile.deleteTuple(idxPageTup); } catch (IOException e) { throw new EventDispatchException( "Couldn't update index " + indexDef.getIndexName() + " for table " + tblFileInfo.getTableName()); } } }
@Override public boolean indexAccessible(final IndexInfo ii) { /* If the following conditions yield true, the index is accessed: * - all query terms are statically available * - no FTTimes option is specified * - explicitly set case, diacritics and stemming match options do not * conflict with index options. */ data = ii.ic.data; final MetaData md = data.meta; final FTOpt fto = ftt.opt; /* Index will be applied if no explicit match options have been set * that conflict with the index options. As a consequence, though, index- * based querying might yield other results than sequential scanning. */ if (occ != null || fto.cs != null && md.casesens == (fto.cs == FTCase.INSENSITIVE) || fto.isSet(DC) && md.diacritics != fto.is(DC) || fto.isSet(ST) && md.stemming != fto.is(ST) || fto.ln != null && !fto.ln.equals(md.language)) return false; // adopt database options to tokenizer fto.copy(md); // estimate costs if text is not known at compile time if (tokens == null) { ii.costs = Math.max(2, data.meta.size / 30); return true; } // summarize number of hits; break loop if no hits are expected final FTLexer ft = new FTLexer(fto); ii.costs = 0; for (byte[] t : tokens) { ft.init(t); while (ft.hasNext()) { final byte[] tok = ft.nextToken(); if (fto.sw != null && fto.sw.contains(tok)) continue; if (fto.is(WC)) { // don't use index if one of the terms starts with a wildcard t = ft.get(); if (t[0] == '.') return false; // don't use index if certain characters or more than 1 dot are found int d = 0; for (final byte w : t) { if (w == '{' || w == '\\' || w == '.' && ++d > 1) return false; } } // favor full-text index requests over exact queries final int costs = data.costs(ft); if (costs != 0) ii.costs += Math.max(2, costs / 100); } } return true; }
@Override public boolean indexAccessible(final IndexInfo ii) throws QueryException { int costs = 0; final ExprList el = new ExprList(exprs.length); for (final Expr expr : exprs) { // check if expression can be rewritten, and if access is not sequential if (!expr.indexAccessible(ii)) return false; // skip expressions without results if (ii.costs == 0) continue; costs += ii.costs; el.add(ii.expr); } // use summarized costs for estimation ii.costs = costs; // no expressions means no costs: expression will later be ignored ii.expr = el.size() == 1 ? el.get(0) : new Union(info, el.finish()); return true; }
@Test public void testReadFromConfigEntry() throws Exception { final IndexInfo info = IndexInfo.fromConfigEntry( stringMap("batch_import.node_index.foo", "exact:file").entrySet().iterator().next()); assertEquals("node_index", info.elementType); assertEquals("foo", info.indexName); assertEquals("exact", info.indexType); assertEquals("file", info.indexFileName); }
/** * This helper method handles the case when a tuple is being added to the table, after the row has * already been added to the table. All indexes on the table are updated to include the new row. * * @param tblFileInfo details of the table being updated * @param ptup the new tuple that was inserted into the table */ private void addRowToIndexes(TableInfo tblFileInfo, PageTuple ptup) { logger.debug("Adding tuple " + ptup + " to indexes for table " + tblFileInfo.getTableName()); // Iterate over the indexes in the table. TableSchema schema = tblFileInfo.getSchema(); for (ColumnRefs indexDef : schema.getIndexes().values()) { TupleLiteral idxTup; try { IndexInfo indexInfo = indexManager.openIndex(tblFileInfo, indexDef.getIndexName()); TupleFile tupleFile = indexInfo.getTupleFile(); TableConstraintType constraintType = indexDef.getConstraintType(); if (constraintType != null && constraintType.isUnique()) { // Check if the index already has a tuple with this value. idxTup = IndexUtils.makeSearchKeyValue(indexDef, ptup, /* findExactTuple */ false); if (IndexUtils.findTupleInIndex(idxTup, tupleFile) != null) { // Adding this row would violate the unique index. throw new IllegalStateException( "Unique index " + "already contains a tuple with this value."); } } idxTup = IndexUtils.makeSearchKeyValue(indexDef, ptup, /* findExactTuple */ true); logger.debug("Adding tuple " + idxTup + " to index " + indexDef.getIndexName()); tupleFile.addTuple(idxTup); } catch (IOException e) { throw new EventDispatchException( "Couldn't update index " + indexDef.getIndexName() + " for table " + tblFileInfo.getTableName(), e); } } }
/** * This method is used to pass an algorithm decorator factory that is used for tracing (for * example). See {@link #checkedRules(Object, Object[], IRuntimeEnv)} for full documentation * * @param target target object * @param params parameters of a test * @param env environment * @param decoratorFactory a decorator factory that will decorate an objects that are used to * calculate a rule * @return iterator over <b>rule indexes</b> - integer iterator. * @see #checkedRules(Object, Object[], IRuntimeEnv) */ protected final IIntIterator checkedRules( Object target, Object[] params, IRuntimeEnv env, DefaultAlgorithmDecoratorFactory decoratorFactory) { // Select rules set using indexed mode // // ICondition[] conditions = table.getConditionRows(); IIntIterator iterator = null; int conditionNumber = info.fromCondition; if (indexRoot == null) { iterator = info.makeRuleIterator(); } else { ARuleIndex index = indexRoot; for (; conditionNumber <= info.toCondition; conditionNumber++) { index = decoratorFactory.create(index, table.getCondition(conditionNumber)); Object testValue = evaluateTestValue(table.getCondition(conditionNumber), target, params, env); DecisionTableRuleNode node = index.findNode(testValue); if (!node.hasIndex()) { iterator = node.getRulesIterator(); conditionNumber += 1; break; } index = node.getNextIndex(); } } for (; conditionNumber <= info.toCondition; conditionNumber++) { ICondition condition = table.getCondition(conditionNumber); IConditionEvaluator evaluator = evaluators[conditionNumber]; IIntSelector sel = evaluator.getSelector(condition, target, params, env); sel = decoratorFactory.create(sel, condition); iterator = iterator.select(sel); } return iterator; }
@Override public boolean indexAccessible(final IndexInfo ii) throws QueryException { final int es = exprs.length; final boolean[] ng = new boolean[es]; int costs = 0; for (final FTExpr expr : exprs) { if (!expr.indexAccessible(ii)) return false; // use worst costs for estimation, as all index results may need to be scanned if (costs < ii.costs) costs = ii.costs; } ii.costs = costs; negated = ng; return true; }