/* * Copyright 2014 Orient Technologies. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.orientechnologies.lucene.operator; import com.orientechnologies.lucene.collections.OFullTextCompositeKey; import com.orientechnologies.lucene.index.OLuceneFullTextIndex; import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.db.ODatabase; import com.orientechnologies.orient.core.db.ODatabaseDocumentInternal; import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; import com.orientechnologies.orient.core.db.record.OIdentifiable; import com.orientechnologies.orient.core.exception.OCommandExecutionException; import com.orientechnologies.orient.core.id.ORID; import com.orientechnologies.orient.core.index.OIndex; import com.orientechnologies.orient.core.index.OIndexCursor; import com.orientechnologies.orient.core.index.OIndexCursorCollectionValue; import com.orientechnologies.orient.core.index.OIndexCursorSingleValue; import com.orientechnologies.orient.core.metadata.schema.OClass; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.sql.OIndexSearchResult; import com.orientechnologies.orient.core.sql.filter.OSQLFilterCondition; import com.orientechnologies.orient.core.sql.filter.OSQLFilterItemField; import com.orientechnologies.orient.core.sql.operator.OIndexReuseType; import com.orientechnologies.orient.core.sql.operator.OQueryTargetOperator; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexableField; import org.apache.lucene.index.memory.MemoryIndex; import org.apache.lucene.search.Query; import java.util.*; public class OLuceneTextOperator extends OQueryTargetOperator { public OLuceneTextOperator() { this("LUCENE", 5, false); } public OLuceneTextOperator(String iKeyword, int iPrecedence, boolean iLogical) { super(iKeyword, iPrecedence, iLogical); } @Override public OIndexCursor executeIndexQuery(OCommandContext iContext, OIndex<?> index, List<Object> keyParams, boolean ascSortOrder) { OIndexCursor cursor; Object indexResult = index.get(new OFullTextCompositeKey(keyParams).setContext(iContext)); if (indexResult == null || indexResult instanceof OIdentifiable) cursor = new OIndexCursorSingleValue((OIdentifiable) indexResult, new OFullTextCompositeKey(keyParams)); else cursor = new OIndexCursorCollectionValue(((Collection<OIdentifiable>) indexResult).iterator(), new OFullTextCompositeKey( keyParams)); iContext.setVariable("$luceneIndex", true); return cursor; } @Override public OIndexReuseType getIndexReuseType(Object iLeft, Object iRight) { return OIndexReuseType.INDEX_OPERATOR; } @Override public ORID getBeginRidRange(Object iLeft, Object iRight) { return null; } @Override public ORID getEndRidRange(Object iLeft, Object iRight) { return null; } @Override public OIndexSearchResult getOIndexSearchResult(OClass iSchemaClass, OSQLFilterCondition iCondition, List<OIndexSearchResult> iIndexSearchResults, OCommandContext context) { return OLuceneOperatorUtil.buildOIndexSearchResult(iSchemaClass, iCondition, iIndexSearchResults, context); } @Override public Collection<OIdentifiable> filterRecords(ODatabase<?> iRecord, List<String> iTargetClasses, OSQLFilterCondition iCondition, Object iLeft, Object iRight) { return null; } @Override public Object evaluateRecord(OIdentifiable iRecord, ODocument iCurrentResult, OSQLFilterCondition iCondition, Object iLeft, Object iRight, OCommandContext iContext) { OLuceneFullTextIndex index = involvedIndex(iRecord, iCurrentResult, iCondition, iLeft, iRight); if (index == null) { throw new OCommandExecutionException("Cannot evaluate lucene condition without index configuration."); } MemoryIndex memoryIndex = (MemoryIndex) iContext.getVariable("_memoryIndex"); if (memoryIndex == null) { memoryIndex = new MemoryIndex(); iContext.setVariable("_memoryIndex", memoryIndex); } memoryIndex.reset(); Document doc = index.buildDocument(iLeft); for (IndexableField field : doc.getFields()) { memoryIndex.addField(field.name(), field.stringValue(), index.analyzer(field.name())); } Query query = null; try { query = index.buildQuery(iRight); } catch (Exception e) { throw new OCommandExecutionException("Error executing lucene query.", e); } return memoryIndex.search(query) > 0.0f; } protected OLuceneFullTextIndex involvedIndex(OIdentifiable iRecord, ODocument iCurrentResult, OSQLFilterCondition iCondition, Object iLeft, Object iRight) { ODocument doc = iRecord.getRecord(); Set<OIndex<?>> classInvolvedIndexes = getDatabase().getMetadata().getIndexManager() .getClassInvolvedIndexes(doc.getClassName(), fields(iCondition)); OLuceneFullTextIndex idx = null; for (OIndex<?> classInvolvedIndex : classInvolvedIndexes) { if (classInvolvedIndex.getInternal() instanceof OLuceneFullTextIndex) { idx = (OLuceneFullTextIndex) classInvolvedIndex.getInternal(); break; } } return idx; } protected static ODatabaseDocumentInternal getDatabase() { return ODatabaseRecordThreadLocal.INSTANCE.get(); } protected Collection<String> fields(OSQLFilterCondition iCondition) { Object left = iCondition.getLeft(); if (left instanceof String) { String fName = (String) left; return Arrays.asList(fName); } if (left instanceof Collection) { Collection<OSQLFilterItemField> f = (Collection<OSQLFilterItemField>) left; List<String> fields = new ArrayList<String>(); for (OSQLFilterItemField field : f) { fields.add(field.toString()); } return fields; } if (left instanceof OSQLFilterItemField) { OSQLFilterItemField fName = (OSQLFilterItemField) left; return Arrays.asList(fName.toString()); } return Collections.emptyList(); } }