/*
* Copyright 2014, Tuplejump Inc.
*
* 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.tuplejump.stargate.lucene;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;
/**
* User: satya
* An indexer which uses an underlying lucene ControlledRealTimeReopenThread Manager
*/
public class BasicIndexer implements Indexer {
private static final Logger logger = LoggerFactory.getLogger(BasicIndexer.class);
public static IndexWriterConfig.OpenMode OPEN_MODE = IndexWriterConfig.OpenMode.CREATE_OR_APPEND;
protected File file;
protected Analyzer analyzer;
protected String indexName;
protected String keyspaceName;
protected String cfName;
protected IndexWriter indexWriter;
protected Directory directory;
protected String vNodeName;
protected SearcherManager searcherManager;
protected AtomicLong records;
public BasicIndexer(AtomicLong records, Analyzer analyzer, String keyspaceName, String cfName, String indexName, String vNodeName) {
try {
this.records = records;
init(analyzer, keyspaceName, cfName, indexName, vNodeName);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void init(Analyzer analyzer, String keyspaceName, String cfName, String indexName, String vNodeName) throws IOException {
this.indexName = indexName;
this.keyspaceName = keyspaceName;
this.cfName = cfName;
this.analyzer = analyzer;
this.vNodeName = vNodeName;
if (logger.isDebugEnabled()) {
logger.debug(indexName + " Lucene analyzer -" + analyzer);
logger.debug(indexName + " Lucene version -" + Properties.luceneVersion);
}
indexWriter = getIndexWriter(Properties.luceneVersion);
searcherManager = new SearcherManager(indexWriter, true, new SearcherFactory());
}
private IndexWriter getIndexWriter(Version luceneV) throws IOException {
file = LuceneUtils.getDirectory(keyspaceName, cfName, indexName, vNodeName);
IndexWriterConfig config = new IndexWriterConfig(analyzer);
config.setRAMBufferSizeMB(128);
// config.setMaxBufferedDocs(128 * 1000);
//config.setInfoStream(System.out);
directory = FSDirectory.open(file.toPath());
if (logger.isInfoEnabled()) {
logger.info(indexName + " SG Index - Opened dir[" + file.getAbsolutePath() + "] - OpenMode[" + OPEN_MODE + "]");
}
return new IndexWriter(directory, config);
}
@Override
public void insert(Iterable<Field> doc) {
if (logger.isDebugEnabled())
logger.debug(indexName + " Indexing fields" + doc);
try {
records.incrementAndGet();
indexWriter.addDocument(doc);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void upsert(Term term, Iterable<Field> doc) {
if (logger.isDebugEnabled())
logger.debug(indexName + "Upsert Indexing fields" + doc);
try {
records.incrementAndGet();
indexWriter.updateDocument(term, doc);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void delete(Term... terms) {
BooleanQuery.Builder q = new BooleanQuery.Builder();
for (Term t : terms) {
if (logger.isDebugEnabled())
logger.debug(indexName + " Delete term - " + t);
q.add(new TermQuery(t), BooleanClause.Occur.MUST);
}
delete(q.build());
}
@Override
public void delete(Query q) {
try {
indexWriter.deleteDocuments(q);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public Analyzer getAnalyzer() {
return analyzer;
}
@Override
public void release(IndexSearcher searcher) {
try {
searcherManager.release(searcher);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public IndexSearcher acquire() {
try {
searcherManager.maybeRefreshBlocking();
return searcherManager.acquire();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean removeIndex() {
if (logger.isInfoEnabled()) {
logger.info("SG BasicIndexer - Removing index - {}", indexName);
}
try {
closeIndex();
LuceneUtils.deleteRecursive(file);
directory.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
return true;
}
@Override
public boolean truncate(long l) {
try {
if (logger.isInfoEnabled()) {
logger.info("SG BasicIndexer - Truncating index - {}", indexName);
}
indexWriter.deleteAll();
return true;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public long liveSize() {
if (indexWriter != null) {
try {
return indexWriter.ramBytesUsed();
} catch (Exception e) {
//ignore
return 0;
}
} else {
return 0;
}
}
@Override
public long size() {
if (indexWriter != null) {
try {
return calcTotalFileSize(directory);
} catch (Exception e) {
//ignore
return 0;
}
} else {
return 0;
}
}
@Override
public long approxRowCount() {
return records.get();
}
@Override
public void close() {
try {
closeIndex();
directory.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void closeIndex() throws IOException {
indexWriter.close();
analyzer.close();
}
@Override
public void commit() {
try {
if (logger.isInfoEnabled()) {
logger.info("SG BasicIndexer - Committing index - {}", indexName);
}
indexWriter.commit();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static long calcTotalFileSize(Directory directory) throws Exception {
long totalFileSize = 0L;
String[] files = directory.listAll();
if (files == null) return totalFileSize;
for (String file : files) {
totalFileSize += directory.fileLength(file);
}
return totalFileSize;
}
}