Package net.sf.logsaw.index.internal

Source Code of net.sf.logsaw.index.internal.LuceneIndexServiceImpl

/*******************************************************************************
* Copyright (c) 2010, 2011 LogSaw project and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    LogSaw project committers - initial API and implementation
*******************************************************************************/
package net.sf.logsaw.index.internal;

import java.io.IOException;
import java.io.StringReader;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

import net.sf.logsaw.core.dialect.ILogDialect;
import net.sf.logsaw.core.dialect.ILogEntryCollector;
import net.sf.logsaw.core.dialect.support.ALogEntryCollector;
import net.sf.logsaw.core.field.ALogEntryField;
import net.sf.logsaw.core.field.ILogEntryFieldVisitor;
import net.sf.logsaw.core.field.Level;
import net.sf.logsaw.core.field.LogEntry;
import net.sf.logsaw.core.field.LogEntryFieldVisitorAdapter;
import net.sf.logsaw.core.field.model.DateLogEntryField;
import net.sf.logsaw.core.field.model.LevelLogEntryField;
import net.sf.logsaw.core.field.model.StringLogEntryField;
import net.sf.logsaw.core.logresource.IHasTimestampPattern;
import net.sf.logsaw.core.logresource.ILogResource;
import net.sf.logsaw.core.query.IRestrictionVisitor;
import net.sf.logsaw.core.query.Operators;
import net.sf.logsaw.core.query.model.DateRestriction;
import net.sf.logsaw.core.query.model.LevelRestriction;
import net.sf.logsaw.core.query.model.StringRestriction;
import net.sf.logsaw.core.query.support.ARestriction;
import net.sf.logsaw.core.util.DateFormatUtils;
import net.sf.logsaw.index.IIndexService;
import net.sf.logsaw.index.IQueryContext;
import net.sf.logsaw.index.IndexPlugin;
import net.sf.logsaw.index.ResultPage;
import net.sf.logsaw.index.SynchronizationResult;

import org.apache.commons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.miscellaneous.LimitTokenCountAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.TopFieldCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A Lucene-based implementation of <code>IIndexService</code>.
*
* @author Philipp Nanz
*/
public class LuceneIndexServiceImpl implements IIndexService {

  private static transient Logger logger = LoggerFactory.getLogger(LuceneIndexServiceImpl.class);

  /* (non-Javadoc)
   * @see net.sf.logsaw.index.IIndexService#synchronize(net.sf.logsaw.core.ILogResource, org.eclipse.core.runtime.IProgressMonitor)
   */
  @Override
  public SynchronizationResult synchronize(ILogResource log, IProgressMonitor monitor) throws CoreException {
    Assert.isNotNull(log, "log"); //$NON-NLS-1$
    if (monitor == null) {
      monitor = new NullProgressMonitor();
    }
   
    Date latestEntryDate = null;
    if (log.getDialect().getFieldProvider().getTimestampField() != null) {
      latestEntryDate = getLatestEntryDate(log); // the barrier timestamp
    }
   
    return updateIndex(log, latestEntryDate, monitor);
  }

  /* (non-Javadoc)
   * @see net.sf.logsaw.index.IIndexService#unlock(net.sf.logsaw.core.ILogResource)
   */
  @Override
  public boolean unlock(ILogResource log) throws CoreException {
    Assert.isNotNull(log, "log"); //$NON-NLS-1$
    try {
      Directory dir = FSDirectory.open(IndexPlugin.getDefault().getIndexFile(log));
      if (IndexWriter.isLocked(dir)) {
        IndexWriter.unlock(dir);
        return true;
      }
      return false;
    } catch (IOException e) {
      // Unexpected exception; wrap with CoreException
      throw new CoreException(new Status(IStatus.ERROR, IndexPlugin.PLUGIN_ID,
          NLS.bind(Messages.LuceneIndexService_error_failedToUnlockIndex,
              new Object[] {log.getName(), e.getLocalizedMessage()}), e));
    }
  }

  /* (non-Javadoc)
   * @see net.sf.logsaw.index.IIndexService#count(net.sf.logsaw.core.ILogResource)
   */
  @Override
  public int count(ILogResource log) throws CoreException {
    Assert.isNotNull(log, "log"); //$NON-NLS-1$
    ARunWithIndexReader<Integer> runnable = new ARunWithIndexReader<Integer>() {
     
      /* (non-Javadoc)
       * @see net.sf.logsaw.index.impl.ARunWithIndexReader#doRunWithIndexReader(org.apache.lucene.index.IndexReader, net.sf.logsaw.core.framework.ILogResource)
       */
      @Override
      protected Integer doRunWithIndexReader(IndexReader reader, ILogResource log) throws CoreException {
        if (reader != null) {
          return Integer.valueOf(reader.numDocs());
        }
        // Index does not exist yet
        return Integer.valueOf(0);
      }
    };
    return runnable.runWithIndexReader(log);
  }

  /* (non-Javadoc)
   * @see net.sf.logsaw.index.IIndexService#size(net.sf.logsaw.core.framework.ILogResource)
   */
  @Override
  public String size(ILogResource log) {
    Assert.isNotNull(log, "log"); //$NON-NLS-1$
    long size = FileUtils.sizeOfDirectory(IndexPlugin.getDefault().getIndexFile(log));
    return FileUtils.byteCountToDisplaySize(size);
  }

  /* (non-Javadoc)
   * @see net.sf.logsaw.index.IIndexService#truncate(net.sf.logsaw.core.framework.ILogResource)
   */
  @Override
  public void truncate(ILogResource log) throws CoreException {
    Assert.isNotNull(log, "log"); //$NON-NLS-1$
    ARunWithIndexWriter<Boolean> runnable = new ARunWithIndexWriter<Boolean>() {
     
      /* (non-Javadoc)
       * @see net.sf.logsaw.index.impl.ARunWithIndexWriter#doRunWithIndexWriter(org.apache.lucene.index.IndexWriter, net.sf.logsaw.core.framework.ILogResource)
       */
      @Override
      protected Boolean doRunWithIndexWriter(IndexWriter writer, ILogResource log) throws CoreException {
        truncate(log, writer);
        return Boolean.TRUE;
      }
    };
    runnable.runWithIndexWriter(log, getAnalyzer(), getMatchVersion());
  }

  /* (non-Javadoc)
   * @see net.sf.logsaw.index.IIndexService#createIndex(net.sf.logsaw.core.logresource.ILogResource)
   */
  @Override
  public void createIndex(ILogResource log) throws CoreException {
    Assert.isNotNull(log, "log"); //$NON-NLS-1$
    Assert.isTrue(log.getPK() == null, "PK must be null"); //$NON-NLS-1$
    log.setPK(UUID.randomUUID().toString());
  }

  /* (non-Javadoc)
   * @see net.sf.logsaw.index.IIndexService#deleteIndex(net.sf.logsaw.core.logresource.ILogResource)
   */
  @Override
  public void deleteIndex(ILogResource log) throws CoreException {
    Assert.isNotNull(log, "log"); //$NON-NLS-1$
    try {
      FileUtils.deleteDirectory(IndexPlugin.getDefault().getIndexFile(log));
    } catch (IOException e) {
      // Throw warning
      throw new CoreException(new Status(IStatus.WARNING, IndexPlugin.PLUGIN_ID,
          NLS.bind(Messages.LuceneIndexService_error_failedToDeleteIndex, log.getName())));
    }
  }

  /* (non-Javadoc)
   * @see net.sf.logsaw.index.IIndexService#createQueryContext(net.sf.logsaw.core.ILogResource)
   */
  @Override
  public IQueryContext createQueryContext(ILogResource log) {
    Assert.isNotNull(log, "log"); //$NON-NLS-1$
    return new LuceneQueryContextImpl(log);
  }

  /* (non-Javadoc)
   * @see net.sf.logsaw.index.IIndexService#query(net.sf.logsaw.index.IQueryContext, java.util.List, int, int)
   */
  @Override
  public ResultPage query(IQueryContext context, final List<ARestriction<?>> restrictions,
      final int offset, final int limit) throws CoreException {
    Assert.isNotNull(context, "context"); //$NON-NLS-1$
    Assert.isTrue(context instanceof LuceneQueryContextImpl,
        "Query context must be of type net.sf.logsaw.index.impl.LuceneQueryContextImpl"); //$NON-NLS-1$
    Assert.isTrue(context.isOpen(), "Query context must be open"); //$NON-NLS-1$
    Assert.isNotNull(restrictions, "restrictions"); //$NON-NLS-1$
   
    ARunWithIndexReader<ResultPage> runnable = new ARunWithIndexReader<ResultPage>() {
     
      /* (non-Javadoc)
       * @see net.sf.logsaw.index.impl.ARunWithIndexReader#doRunWithIndexReader(org.apache.lucene.index.IndexReader, net.sf.logsaw.core.framework.ILogResource)
       */
      @Override
      protected ResultPage doRunWithIndexReader(IndexReader reader, ILogResource log) throws CoreException {
        if (reader == null) {
          // Index does not exist yet
          return new ResultPage();
        }
       
        try {
          IndexSearcher searcher = new IndexSearcher(reader);
          Sort sort = new Sort(new SortField[] {SortField.FIELD_DOC});
          TopFieldCollector collector = TopFieldCollector.create(
              sort, offset + limit, false, false, false, true);
          // TODO Investigate use of searchAfter
          searcher.search(convertToQuery(restrictions), collector);
          List<LogEntry> result = new LinkedList<LogEntry>();
          collectHits(searcher, collector.topDocs(offset), log.getDialect(), result);
          return new ResultPage(result, offset, collector.getTotalHits());
        } catch (IOException e) {
          // Unexpected exception; wrap with CoreException
          throw new CoreException(new Status(IStatus.ERROR, IndexPlugin.PLUGIN_ID,
              NLS.bind(Messages.LuceneIndexService_error_failedToReadIndex,
                  new Object[] {log.getName(), e.getLocalizedMessage()}), e));
        }
      }
    };
    runnable.setQueryContext((LuceneQueryContextImpl) context);
    return runnable.runWithIndexReader(context.getLogResource());
  }

  /**
   * Returns the Lucene analyzer to use for indexing text fields.
   * <p>
   * Defaults to a <code>StandardAnalyzer</code> with Lucene 4.1 semantics.
   *
   * @return the Lucene analyzer to use
   */
  protected Analyzer getAnalyzer() {
    return new LimitTokenCountAnalyzer(new StandardAnalyzer(getMatchVersion()), 10000);
  }

  /**
   * Returns the Lucene match version.
   * <p>
   * Defaults to Lucene 4.1 semantics.
   *
   * @return the Lucene match version to use
   */
  protected Version getMatchVersion() {
    return Version.LUCENE_41;
  }

  /*
   * PRIVATE METHODS
   */

  private Date getLatestEntryDate(ILogResource log) throws CoreException {
    if (!hasDateComponent(log)) {
      return null;
    }
   
    ARunWithIndexReader<Date> runnable = new ARunWithIndexReader<Date>() {
     
      /* (non-Javadoc)
       * @see net.sf.logsaw.index.impl.ARunWithIndexReader#doRunWithIndexReader(org.apache.lucene.index.IndexReader, net.sf.logsaw.core.framework.ILogResource)
       */
      @Override
      protected Date doRunWithIndexReader(IndexReader reader, ILogResource log) throws CoreException {
        if (reader == null) {
          // Index does not exist yet
          return null;
        }
        int i = reader.maxDoc();
        if (i > 0) {
          try {
            Document doc = reader.document(i - 1);
            String val = doc.get(log.getDialect().getFieldProvider().getTimestampField().getKey());
            return log.getDialect().getFieldProvider().getTimestampField().fromIndexedValue(val);
          } catch (IOException e) {
            // Unexpected exception; wrap with CoreException
            throw new CoreException(new Status(IStatus.ERROR, IndexPlugin.PLUGIN_ID,
                NLS.bind(Messages.LuceneIndexService_error_failedToReadIndex,
                    new Object[] {log.getName(), e.getLocalizedMessage()}), e));
          }
        }
        return null;
      }
    };
    return runnable.runWithIndexReader(log);
  }

  private boolean hasDateComponent(ILogResource log) {
    IHasTimestampPattern hasPattern =
        (IHasTimestampPattern) log.getDialect().getAdapter(IHasTimestampPattern.class);
    if ((hasPattern != null) && (hasPattern.getTimestampPattern() != null)) {
      return DateFormatUtils.hasDateComponent(hasPattern.getTimestampPattern());
    }
    return true;
  }

  private SynchronizationResult updateIndex(ILogResource log, final Date latestEntryDate,
      final IProgressMonitor monitor) throws CoreException {
    // Measure runtime
    final long startTime = System.currentTimeMillis();
   
    ARunWithIndexWriter<SynchronizationResult> runnable = new ARunWithIndexWriter<SynchronizationResult>() {
     
      /* (non-Javadoc)
       * @see net.sf.logsaw.index.impl.ARunWithIndexWriter#doRunWithIndexWriter(org.apache.lucene.index.IndexWriter, net.sf.logsaw.core.framework.ILogResource)
       */
      @Override
      protected SynchronizationResult doRunWithIndexWriter(final IndexWriter writer,
          final ILogResource log) throws CoreException {
        ILogEntryCollector collector = new ALogEntryCollector(monitor) {
         
          /* (non-Javadoc)
           * @see net.sf.logsaw.core.framework.support.ALogEntryCollector#doCollect(net.sf.logsaw.core.model.LogEntry)
           */
          @Override
          protected boolean doCollect(final LogEntry entry)
              throws IOException {
            final Document doc = new Document();
            if (latestEntryDate != null) {
              Date d = entry.get(log.getDialect().getFieldProvider().getTimestampField());
              if (!d.after(latestEntryDate)) {
                // Skip entry because it was already indexed
                return false;
              }
            }
           
            // Setup visitor
            ILogEntryFieldVisitor visitor = new ILogEntryFieldVisitor() {

              /* (non-Javadoc)
               * @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.StringLogEntryField)
               */
              @Override
              public void visit(StringLogEntryField fld) {
                // Decide whether to analyze the field
                if (fld.isAnalyzed()) {
                  doc.add(new TextField(fld.getKey(),
                      fld.toIndexedValue(entry.get(fld)),
                      Field.Store.YES));
                } else {
                  doc.add(new StringField(fld.getKey(),
                      fld.toIndexedValue(entry.get(fld)),
                      Field.Store.YES));
                }
              }

              /* (non-Javadoc)
               * @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.LevelLogEntryField)
               */
              @Override
              public void visit(LevelLogEntryField fld) {
                Level lvl = entry.get(fld);
                Assert.isTrue(lvl.getValue() > 0, "Level value must be a positive integer"); //$NON-NLS-1$
                doc.add(new IntField(
                    fld.getKey(), fld.toIndexedValue(lvl), Field.Store.YES));
              }

              /* (non-Javadoc)
               * @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.DateLogEntryField)
               */
              @Override
              public void visit(DateLogEntryField fld) {
                doc.add(new LongField(
                    fld.getKey(), fld.toIndexedValue(entry.get(fld)), Field.Store.YES));
              }
            };
            for (ALogEntryField<?, ?> fld : log.getDialect().getFieldProvider().getAllFields()) {
              if (entry.contains(fld)) {
                fld.visit(visitor);
              }
            }
            writer.addDocument(doc);
            return true;
          }
        };
       
        if (log.getDialect().getFieldProvider().getTimestampField() == null) {
          // We have no barrier timestamp, so perform truncate to avoid duplicates
          truncate(log, writer);
         
          collector.addMessage(new Status(IStatus.INFO, IndexPlugin.PLUGIN_ID,
              Messages.LuceneIndexService_info_autoTruncate_noTimestampField));
        } else if (!hasDateComponent(log)) {
          // The date format only contains time components, so perform truncate to avoid duplicates
          truncate(log, writer);
         
          collector.addMessage(new Status(IStatus.INFO, IndexPlugin.PLUGIN_ID,
              Messages.LuceneIndexService_info_autoTruncate_noDateComponent));
        }
       
        // Perform synchronize
        log.synchronize(collector, monitor);
        return new SynchronizationResult(monitor.isCanceled(), collector.getTotalCollected(),
            System.currentTimeMillis() - startTime, collector.getMessages());
      }
    };
    return runnable.runWithIndexWriter(log, getAnalyzer(), getMatchVersion());
  }

  private void truncate(ILogResource log, IndexWriter writer) throws CoreException {
    try {
      writer.deleteAll();
      writer.commit();
    } catch (Exception e) {
      // Unexpected exception; wrap with CoreException
      throw new CoreException(new Status(IStatus.ERROR, IndexPlugin.PLUGIN_ID,
          NLS.bind(Messages.LuceneIndexService_error_failedToTruncateIndex,
              new Object[] {log.getName(), e.getLocalizedMessage()}), e));
    }
  }

  private Query convertToQuery(final List<ARestriction<?>> restrictions) {
    if (restrictions.isEmpty()) {
      // Unrestricted
      return new MatchAllDocsQuery();
    }
    final BooleanQuery query = new BooleanQuery();
   
    // Setup visitor
    IRestrictionVisitor visitor = new IRestrictionVisitor() {

      /* (non-Javadoc)
       * @see net.sf.logsaw.core.query.IRestrictionVisitor#visit(net.sf.logsaw.core.query.DateRestriction)
       */
      @Override
      public void visit(final DateRestriction restriction) {
        ILogEntryFieldVisitor visitor = new LogEntryFieldVisitorAdapter() {
          /* (non-Javadoc)
           * @see net.sf.logsaw.core.model.LogEntryFieldVisitorAdapter#visit(net.sf.logsaw.core.model.DateLogEntryField)
           */
          @Override
          public void visit(DateLogEntryField fld) {
            if (restriction.getOperator().equals(Operators.OPERATOR_BEFORE)) {
              query.add(NumericRangeQuery.newLongRange(
                  fld.getKey(), null,
                  fld.toIndexedValue(restriction.getValue()),
                  false, false), Occur.MUST);
            } else if (restriction.getOperator().equals(Operators.OPERATOR_AFTER)) {
              query.add(NumericRangeQuery.newLongRange(
                  fld.getKey(),
                  fld.toIndexedValue(restriction.getValue()), null,
                  false, false), Occur.MUST);
            }
          }
        };
        restriction.getField().visit(visitor);
      }

      /* (non-Javadoc)
       * @see net.sf.logsaw.core.query.IRestrictionVisitor#visit(net.sf.logsaw.core.query.LevelRestriction)
       */
      @Override
      public void visit(final LevelRestriction restriction) {
        ILogEntryFieldVisitor visitor = new LogEntryFieldVisitorAdapter() {
          /* (non-Javadoc)
           * @see net.sf.logsaw.core.model.LogEntryFieldVisitorAdapter#visit(net.sf.logsaw.core.model.LevelLogEntryField)
           */
          @Override
          public void visit(LevelLogEntryField fld) {
            if (restriction.getOperator().equals(Operators.OPERATOR_GREATER_THAN)) {
              query.add(NumericRangeQuery.newIntRange(
                  fld.getKey(),
                  restriction.getValue().getValue(), null,
                  false, false), Occur.MUST);
            } else if (restriction.getOperator().equals(Operators.OPERATOR_LESS_THAN)) {
              query.add(NumericRangeQuery.newIntRange(
                  fld.getKey(), null,
                  fld.toIndexedValue(restriction.getValue()),
                  false, false), Occur.MUST);
            } else if (restriction.getOperator().equals(Operators.OPERATOR_EQUALS)) {
              query.add(NumericRangeQuery.newIntRange(
                  fld.getKey(), fld.toIndexedValue(restriction.getValue()),
                  fld.toIndexedValue(restriction.getValue()),
                  true, true), Occur.MUST);
            } else if (restriction.getOperator().equals(Operators.OPERATOR_NOT_EQUALS)) {
              query.add(NumericRangeQuery.newIntRange(
                  fld.getKey(), fld.toIndexedValue(restriction.getValue()),
                  fld.toIndexedValue(restriction.getValue()),
                  true, true), Occur.MUST_NOT);
              if (isAllNegative(restrictions) && restrictions.get(0).equals(restriction)) {
                // By design Lucene does not process negative-only queries
                query.add(new MatchAllDocsQuery(), Occur.SHOULD);
              }
            }
          }
        };
        restriction.getField().visit(visitor);
      }

      /* (non-Javadoc)
       * @see net.sf.logsaw.core.query.IRestrictionVisitor#visit(net.sf.logsaw.core.query.StringRestriction)
       */
      @Override
      public void visit(final StringRestriction restriction) {
        if (restriction.getOperator().equals(Operators.OPERATOR_CONTAINS)) {
          try {
            // Setup phrase query with tokenized query string
            PhraseQuery phrase = new PhraseQuery();
            fillPhraseQuery(phrase, getAnalyzer(),
                restriction.getField().getKey(), restriction.getValue());
            query.add(phrase, Occur.MUST);
          } catch (IOException e) {
            logger.error(e.getLocalizedMessage(), e);
          }
        } else if (restriction.getOperator().equals(Operators.OPERATOR_NOT_CONTAINS)) {
          try {
            // Setup phrase query with tokenized query string
            PhraseQuery phrase = new PhraseQuery();
            fillPhraseQuery(phrase, getAnalyzer(),
                restriction.getField().getKey(), restriction.getValue());
            query.add(phrase, Occur.MUST_NOT);
            if (isAllNegative(restrictions) && restrictions.get(0).equals(restriction)) {
              // By design Lucene does not process negative-only queries
              query.add(new MatchAllDocsQuery(), Occur.SHOULD);
            }
          } catch (IOException e) {
            logger.error(e.getLocalizedMessage(), e);
          }
        } else if (restriction.getOperator().equals(Operators.OPERATOR_EQUALS)) {
          query.add(new TermQuery(new Term(restriction.getField().getKey(),
              restriction.getValue())), Occur.MUST);
        } else if (restriction.getOperator().equals(Operators.OPERATOR_NOT_EQUALS)) {
          query.add(new TermQuery(new Term(restriction.getField().getKey(),
              restriction.getValue())), Occur.MUST_NOT);
          if (isAllNegative(restrictions) && restrictions.get(0).equals(restriction)) {
            // By design Lucene does not process negative-only queries
            query.add(new MatchAllDocsQuery(), Occur.SHOULD);
          }
        } else if (restriction.getOperator().equals(Operators.OPERATOR_BEGINS_WITH)) {
          query.add(new PrefixQuery(new Term(restriction.getField().getKey(),
              restriction.getValue())), Occur.MUST);
        } else if (restriction.getOperator().equals(Operators.OPERATOR_NOT_BEGINS_WITH)) {
          query.add(new PrefixQuery(new Term(restriction.getField().getKey(),
              restriction.getValue())), Occur.MUST_NOT);
          if (isAllNegative(restrictions) && restrictions.get(0).equals(restriction)) {
            // By design Lucene does not process negative-only queries
            query.add(new MatchAllDocsQuery(), Occur.SHOULD);
          }
        }
      }
    };
    for (ARestriction<?> restriction : restrictions) {
      restriction.visit(visitor);
    }
    return query;
  }

  private void fillPhraseQuery(PhraseQuery phrase, Analyzer analyzer, String fld, String val) throws IOException {
    TokenStream ts = analyzer.tokenStream(fld, new StringReader(val));
    try {
      ts.reset();
      // Iterate over tokens and treat each token as term
      int pos = 0;
      while (ts.incrementToken()) {
        CharTermAttribute t = ts.getAttribute(CharTermAttribute.class);
        PositionIncrementAttribute p = ts.getAttribute(PositionIncrementAttribute.class);
        pos += p.getPositionIncrement();
        phrase.add(new Term(fld, t.toString()), pos - 1);
      }
      // End-of-stream clean-up
      ts.end();
    } finally {
      ts.close();
    }
  }

  private boolean isAllNegative(List<ARestriction<?>> restrictions) {
    for (ARestriction<?> restriction : restrictions) {
      if (!restriction.getOperator().isNegative()) {
        return false;
      }
    }
    return true;
  }

  private void collectHits(IndexSearcher searcher, TopDocs hits,
      ILogDialect dialect, List<LogEntry> result) throws IOException {
    for (int i = 0; i < hits.scoreDocs.length; i++) {
      final Document doc = searcher.doc(hits.scoreDocs[i].doc);
      final LogEntry entry = new LogEntry();
     
      // Setup visitor
      ILogEntryFieldVisitor visitor = new ILogEntryFieldVisitor() {

        /* (non-Javadoc)
         * @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.StringLogEntryField)
         */
        @Override
        public void visit(StringLogEntryField fld) {
          String value = doc.get(fld.getKey());
          if (value != null) {
            entry.put(fld, fld.fromIndexedValue(value));
          }
        }

        /* (non-Javadoc)
         * @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.LevelLogEntryField)
         */
        @Override
        public void visit(LevelLogEntryField fld) {
          String value = doc.get(fld.getKey());
          if (value != null) {
            entry.put(fld, fld.fromIndexedValue(value));
          }
        }

        /* (non-Javadoc)
         * @see net.sf.logsaw.core.model.ILogEntryFieldVisitor#visit(net.sf.logsaw.core.model.DateLogEntryField)
         */
        @Override
        public void visit(DateLogEntryField fld) {
          String value = doc.get(fld.getKey());
          if (value != null) {
            entry.put(fld, fld.fromIndexedValue(value));
         
        }
      };
      for (ALogEntryField<?, ?> field : dialect.getFieldProvider().getAllFields()) {
        field.visit(visitor);
      }
      result.add(entry);
    }
  }
}
TOP

Related Classes of net.sf.logsaw.index.internal.LuceneIndexServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.