Nitrite db = Nitrite.builder()
.compressed()
.openOrCreate("user", "password");
public class NitriteBuilder
extends java.lang.Object
A builder utility to create a Nitrite
database instance.
Nitrite db = Nitrite.builder()
.compressed()
.openOrCreate("user", "password");
Nitrite db = Nitrite.builder()
.filePath("/tmp/mydb.db")
.openOrCreate();
Nitrite db = Nitrite.builder()
.filePath("/tmp/mydb.db")
.openOrCreate("user", "password");
TextIndexingService
Nitrite db = Nitrite.builder()
.textIndexingService(new LuceneService())
.openOrCreate("user", "password");
/*
*
* Copyright 2017-2018 Nitrite author or authors.
*
* 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 org.dizitart.no2.services;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.dizitart.no2.NitriteId;
import org.dizitart.no2.exceptions.IndexingException;
import org.dizitart.no2.fulltext.TextIndexingService;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
import static org.dizitart.no2.exceptions.ErrorMessage.errorMessage;
import static org.dizitart.no2.util.StringUtils.isNullOrEmpty;
public class LuceneService implements TextIndexingService {
private static final String CONTENT_ID = "content_id";
private static final int MAX_SEARCH = Byte.MAX_VALUE;
private IndexWriter indexWriter;
private ObjectMapper keySerializer;
private Analyzer analyzer;
private Directory indexDirectory;
public LuceneService() {
try {
this.keySerializer = new ObjectMapper();
keySerializer.setVisibility(keySerializer
.getSerializationConfig()
.getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE));
indexDirectory = new RAMDirectory();
analyzer = new StandardAnalyzer();
IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
indexWriter = new IndexWriter(indexDirectory, iwc);
commit();
} catch (IOException e) {
throw new IndexingException(errorMessage("could not create full-text index", 0), e);
} catch (VirtualMachineError vme) {
handleVirtualMachineError(vme);
}
}
@Override
public void createIndex(NitriteId id, String field, String text) {
try {
Document document = new Document();
String jsonId = keySerializer.writeValueAsString(id);
Field contentField = new TextField(field, text, Field.Store.NO);
Field idField = new StringField(CONTENT_ID, jsonId, Field.Store.YES);
document.add(idField);
document.add(contentField);
synchronized (this) {
indexWriter.addDocument(document);
commit();
}
} catch (IOException ioe) {
throw new IndexingException(errorMessage("could not write full-text index data for " + text, 0), ioe);
} catch (VirtualMachineError vme) {
handleVirtualMachineError(vme);
}
}
@Override
public void updateIndex(NitriteId id, String field, String text) {
try {
String jsonId = keySerializer.writeValueAsString(id);
Document document = getDocument(jsonId);
if (document == null) {
document = new Document();
Field idField = new StringField(CONTENT_ID, jsonId, Field.Store.YES);
document.add(idField);
}
Field contentField = new TextField(field, text, Field.Store.YES);
document.add(contentField);
synchronized (this) {
indexWriter.updateDocument(new Term(CONTENT_ID, jsonId), document);
commit();
}
} catch (IOException ioe) {
throw new IndexingException(errorMessage("could not update full-text index for " + text, 0), ioe);
} catch (VirtualMachineError vme) {
handleVirtualMachineError(vme);
}
}
@Override
public void deleteIndex(NitriteId id, String field, String text) {
try {
String jsonId = keySerializer.writeValueAsString(id);
Term idTerm = new Term(CONTENT_ID, jsonId);
synchronized (this) {
indexWriter.deleteDocuments(idTerm);
commit();
}
} catch (IOException ioe) {
throw new IndexingException(errorMessage("could not remove full-text index for " + id, 0));
} catch (VirtualMachineError vme) {
handleVirtualMachineError(vme);
}
}
@Override
public void deleteIndexesByField(String field) {
if (!isNullOrEmpty(field)) {
try {
Query query;
QueryParser parser = new QueryParser(field, analyzer);
parser.setAllowLeadingWildcard(true);
try {
query = parser.parse("*");
} catch (ParseException e) {
throw new IndexingException(errorMessage("could not remove full-text index for value " + field, 0));
}
synchronized (this) {
indexWriter.deleteDocuments(query);
commit();
}
} catch (IOException ioe) {
throw new IndexingException(errorMessage("could not remove full-text index for value " + field, 0));
} catch (VirtualMachineError vme) {
handleVirtualMachineError(vme);
}
}
}
@Override
public Set<NitriteId> searchByIndex(String field, String searchString) {
IndexReader indexReader = null;
try {
QueryParser parser = new QueryParser(field, analyzer);
parser.setAllowLeadingWildcard(true);
Query query = parser.parse("*" + searchString + "*");
indexReader = DirectoryReader.open(indexDirectory);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
TopScoreDocCollector collector = TopScoreDocCollector.create(MAX_SEARCH);
indexSearcher.search(query, collector);
TopDocs hits = collector.topDocs(0, MAX_SEARCH);
Set<NitriteId> keySet = new LinkedHashSet<>();
if (hits != null) {
ScoreDoc[] scoreDocs = hits.scoreDocs;
if (scoreDocs != null) {
for (ScoreDoc scoreDoc : scoreDocs) {
Document document = indexSearcher.doc(scoreDoc.doc);
String jsonId = document.get(CONTENT_ID);
NitriteId nitriteId = keySerializer.readValue(jsonId, NitriteId.class);
keySet.add(nitriteId);
}
}
}
return keySet;
} catch (IOException | ParseException e) {
throw new IndexingException(errorMessage("could not search on full-text index", 0), e);
} finally {
try {
if (indexReader != null)
indexReader.close();
} catch (IOException ignored) {
// ignored
}
}
}
private Document getDocument(String jsonId) {
IndexReader indexReader = null;
try {
Term idTerm = new Term(CONTENT_ID, jsonId);
TermQuery query = new TermQuery(idTerm);
indexReader = DirectoryReader.open(indexDirectory);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
TopScoreDocCollector collector = TopScoreDocCollector.create(MAX_SEARCH);
indexSearcher.search(query, collector);
TopDocs hits = collector.topDocs(0, MAX_SEARCH);
Document document = null;
if (hits != null) {
ScoreDoc[] scoreDocs = hits.scoreDocs;
if (scoreDocs != null) {
for (ScoreDoc scoreDoc : scoreDocs) {
document = indexSearcher.doc(scoreDoc.doc);
}
}
}
return document;
} catch (IOException e) {
throw new IndexingException(errorMessage("could not search on full-text index", 0), e);
} finally {
try {
if (indexReader != null)
indexReader.close();
} catch (IOException ignored) {
// ignored
}
}
}
@Override
public void drop() {
try {
indexDirectory = new RAMDirectory();
analyzer = new StandardAnalyzer();
IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
indexWriter = new IndexWriter(indexDirectory, iwc);
commit();
} catch (IOException e) {
throw new IndexingException(errorMessage("could not drop full-text index", 0), e);
}
}
@Override
public void clear() {
try {
indexWriter.deleteAll();
commit();
} catch (IOException e) {
throw new IndexingException(errorMessage("could not clear full-text index", 0), e);
}
}
private void handleVirtualMachineError(VirtualMachineError vme) {
if (indexWriter != null) {
try {
indexWriter.close();
} catch (IOException ioe) {
// ignore it
}
}
throw vme;
}
private synchronized void commit() throws IOException {
indexWriter.commit();
}
}
Nitrite
Modifier and Type | Method and Description |
---|---|
NitriteBuilder |
autoCommitBufferSize(int size)
Sets the size of the write buffer, in KB disk space (for file-based
stores).
|
NitriteBuilder |
compressed()
Compresses data before writing using the LZF algorithm.
|
NitriteBuilder |
disableAutoCommit()
Disables auto commit.
|
NitriteBuilder |
disableAutoCompact()
Disables auto compact before close.
|
NitriteBuilder |
disableShutdownHook()
Disables JVM shutdown hook for closing the database gracefully.
|
NitriteBuilder |
filePath(java.io.File file)
Sets file name for the file based store.
|
NitriteBuilder |
filePath(java.lang.String path)
Sets file name for the file based store.
|
NitriteBuilder |
nitriteMapper(NitriteMapper nitriteMapper)
Sets a custom
NitriteMapper implementation. |
Nitrite |
openOrCreate()
Opens or creates a new database.
|
Nitrite |
openOrCreate(java.lang.String userId,
java.lang.String password)
Opens or creates a new database.
|
NitriteBuilder |
readOnly()
Opens the file in read-only mode.
|
NitriteBuilder |
registerModule(com.fasterxml.jackson.databind.Module module)
Registers a jackson
Module to the JacksonFacade . |
NitriteBuilder |
textIndexingService(TextIndexingService textIndexingService)
Sets a custom
TextIndexingService implementation to be used
during full text indexing and full text search. |
NitriteBuilder |
textTokenizer(TextTokenizer textTokenizer)
Sets a custom
TextTokenizer for the in-built TextIndexingService . |
public NitriteBuilder filePath(java.lang.String path)
Sets file name for the file based store. If file
is null
the builder will create an in-memory database.
path
- the name of the file store.NitriteBuilder
instance.public NitriteBuilder filePath(java.io.File file)
Sets file name for the file based store. If file
is null
the builder will create an in-memory database.
file
- the name of the file store.NitriteBuilder
instance.public NitriteBuilder autoCommitBufferSize(int size)
Sets the size of the write buffer, in KB disk space (for file-based stores). Unless auto-commit is disabled, changes are automatically saved if there are more than this amount of changes.
When the values is set to 0 or lower, it will assume the default value - 1024 KB.
If auto commit is disabled by disableAutoCommit() ,
then buffer size has not effect.
|
size
- the buffer size in KBNitriteBuilder
instance.public NitriteBuilder readOnly()
Opens the file in read-only mode. In this case, a shared lock will be acquired to ensure the file is not concurrently opened in write mode.
If this option is not used, the file is locked exclusively.
A file store may only be opened once in every JVM (no matter whether it is opened in read-only or read-write mode), because each file may be locked only once in a process. |
NitriteBuilder
instance.public NitriteBuilder compressed()
Compresses data before writing using the LZF algorithm. This will save about 50% of the disk space, but will slow down read and write operations slightly.
This setting only affects writes; it is not necessary to enable compression when reading, even if compression was enabled when writing. |
NitriteBuilder
instance.public NitriteBuilder disableAutoCommit()
Disables auto commit. If disabled, unsaved changes will not be written
into disk until Nitrite.commit()
is called.
By default auto commit is enabled.
NitriteBuilder
instance.public NitriteBuilder disableAutoCompact()
Disables auto compact before close. If disabled, compaction will not be performed. Disabling would increase close performance.
By default auto compact is enabled.
NitriteBuilder
instance.public NitriteBuilder textIndexingService(TextIndexingService textIndexingService)
Sets a custom TextIndexingService
implementation to be used
during full text indexing and full text search. If not set, the default
text indexer will be used.
If user does not want to use the default text indexer and instead like to use
third-party full text search engine like apache lucene, a custom
|
textIndexingService
- the TextIndexingService
implementation.NitriteBuilder
instance.TextIndexingService
,
Filters.text(String, String)
,
PersistentCollection.createIndex(String, IndexOptions)
public NitriteBuilder textTokenizer(TextTokenizer textTokenizer)
Sets a custom TextTokenizer
for the in-built TextIndexingService
.
If not set, a default text tokenizer EnglishTextTokenizer
is used. The default tokenizer works on english language only.
For non-english languages like chinese, japanese etc.,
a UniversalTextTokenizer
needs to be set here.
This settings is only applicable when in-built If a custom |
textTokenizer
- the TextTokenizer
implementation.NitriteBuilder
instance.EnglishTextTokenizer
,
UniversalTextTokenizer
public NitriteBuilder nitriteMapper(NitriteMapper nitriteMapper)
Sets a custom NitriteMapper
implementation. If not set, a default
jackson based mapper JacksonMapper
will
be used.
nitriteMapper
- a NitriteMapper
implementationNitriteBuilder
instance.GenericMapper
,
JacksonMapper
public NitriteBuilder disableShutdownHook()
Disables JVM shutdown hook for closing the database gracefully.
NitriteBuilder
instance.public NitriteBuilder registerModule(com.fasterxml.jackson.databind.Module module)
Registers a jackson Module
to the JacksonFacade
.
This is only useful when the default |
module
- jackson module to registerNitriteBuilder
instance.JacksonFacade
,
JacksonMapper
,
NitriteMapper
,
GenericMapper
public Nitrite openOrCreate()
Opens or creates a new database. If it is an in-memory store, then it will create a new one. If it is a file based store, and if the file does not exists, then it will create a new file store and open; otherwise it will open the existing file store.
If the database is corrupted somehow then at the time of opening, it will
try to repair it using the last known good version. If still it fails to
recover, then it will throw a It also adds a JVM shutdown hook to the database instance. If JVM exists
before closing the database properly by calling |
NitriteIOException
- if unable to create a new in-memory database.NitriteIOException
- if the database is corrupt and recovery fails.java.lang.IllegalArgumentException
- if the directory does not exist.public Nitrite openOrCreate(java.lang.String userId, java.lang.String password)
Opens or creates a new database. If it is an in-memory store, then it will create a new one. If it is a file based store, and if the file does not exists, then it will create a new file store and open; otherwise it will open the existing file store.
While creating a new database, it will use the specified user credentials. While opening an existing database, it will use the specified credentials to open it.
If the database is corrupted somehow then at the time of opening, it will
try to repair it using the last known good version. If still it fails to
recover, then it will throw a It also adds a JVM shutdown hook to the database instance. If JVM exists
before closing the database properly by calling |
userId
- the user idpassword
- the passwordSecurityException
- if the user credentials are wrong or one of them is empty string.NitriteIOException
- if unable to create a new in-memory database.NitriteIOException
- if the database is corrupt and recovery fails.NitriteIOException
- if the directory does not exist.