org.hibernate.search.engine.impl.LuceneOptionsImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-search-engine Show documentation
Show all versions of hibernate-search-engine Show documentation
Core of the Object/Lucene mapper, query engine and index management
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.search.engine.impl;
import org.apache.lucene.document.CompressionTools;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.DoubleDocValuesField;
import org.apache.lucene.document.DoubleField;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.TermVector;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.FloatDocValuesField;
import org.apache.lucene.document.FloatField;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.SortedDocValuesField;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.util.BytesRef;
import org.hibernate.search.annotations.Store;
import org.hibernate.search.bridge.LuceneOptions;
import org.hibernate.search.bridge.spi.NullMarker;
import org.hibernate.search.engine.metadata.impl.DocumentFieldMetadata;
import org.hibernate.search.exception.SearchException;
import org.hibernate.search.util.StringHelper;
/**
* A wrapper class for Lucene parameters needed for indexing.
*
* @author Hardy Ferentschik
* @author Sanne Grinovero
* @author Gustavo Fernandes
*/
public class LuceneOptionsImpl implements LuceneOptions {
private static final FieldType TYPE_COMPRESSED = new FieldType();
static {
TYPE_COMPRESSED.setTokenized( false );
TYPE_COMPRESSED.setOmitNorms( true );
TYPE_COMPRESSED.setIndexOptions( IndexOptions.NONE );
TYPE_COMPRESSED.setStored( true );
TYPE_COMPRESSED.freeze();
}
private final boolean storeCompressed;
private final boolean storeUncompressed;
private boolean documentBoostApplied = false; //needs to be applied only once
private final float fieldLevelBoost;
/**
* Boost inherited from the parent structure of the given field: the document-level boost in case of a top-level
* field, the product of the document-level boost and the boost(s) of the parent embeddable(s) in case of an
* embedded field
*/
private final float inheritedBoost;
private final Index indexMode;
private final TermVector termVector;
private final Store storeType;
private final String indexNullAs;
public LuceneOptionsImpl(DocumentFieldMetadata fieldMetadata, float fieldLevelBoost, float inheritedBoost) {
this.inheritedBoost = inheritedBoost;
this.indexMode = fieldMetadata.getIndex();
this.termVector = fieldMetadata.getTermVector();
this.fieldLevelBoost = fieldLevelBoost;
this.storeType = fieldMetadata.getStore();
this.storeCompressed = this.storeType.equals( Store.COMPRESS );
this.storeUncompressed = this.storeType.equals( Store.YES );
NullMarker nullMarker = fieldMetadata.getNullMarkerCodec().getNullMarker();
this.indexNullAs = nullMarker == null ? null : nullMarker.nullRepresentedAsString();
}
public LuceneOptionsImpl(Index indexMode, TermVector termVector, Store store, String indexNullAs, float fieldLevelBoost, float inheritedBoost) {
this.inheritedBoost = inheritedBoost;
this.indexMode = indexMode;
this.termVector = termVector;
this.fieldLevelBoost = fieldLevelBoost;
this.storeType = store;
this.storeCompressed = this.storeType.equals( Store.COMPRESS );
this.storeUncompressed = this.storeType.equals( Store.YES );
this.indexNullAs = indexNullAs;
}
@Override
public void addFieldToDocument(String name, String indexedString, Document document) {
//Do not add fields on empty strings, seems a sensible default in most situations
if ( StringHelper.isNotEmpty( indexedString ) ) {
if ( !( indexMode.equals( Index.NO ) && storeCompressed ) ) {
standardFieldAdd( name, indexedString, document );
}
if ( storeCompressed ) {
compressedFieldAdd( name, indexedString, document );
}
}
}
private void standardFieldAdd(String name, String indexedString, Document document) {
// Non-stored, non-indexed field may be declared for sorting purposes; don't add it to the document
if ( storeType == Store.NO && indexMode == Index.NO ) {
return;
}
Field field = new Field( name, indexedString, storeUncompressed ? Field.Store.YES : Field.Store.NO, indexMode, termVector );
setBoost( field );
document.add( field );
}
private void compressedFieldAdd(String name, String indexedString, Document document) {
// Non-stored, non-indexed field may be declared for sorting purposes; don't add it to the document
if ( storeType == Store.NO && indexMode == Index.NO ) {
return;
}
byte[] compressedString = CompressionTools.compressString( indexedString );
// indexed is implicitly set to false when using byte[]
Field field = new Field( name, compressedString, TYPE_COMPRESSED );
document.add( field );
}
@Override
@Deprecated
public float getBoost() {
return fieldLevelBoost;
}
@Override
public String indexNullAs() {
return indexNullAs;
}
@Override
public boolean isCompressed() {
return storeCompressed;
}
@Override
public Index getIndex() {
return this.indexMode;
}
@Override
public org.apache.lucene.document.Field.Store getStore() {
if ( storeUncompressed || storeCompressed ) {
return org.apache.lucene.document.Field.Store.YES;
}
else {
return org.apache.lucene.document.Field.Store.NO;
}
}
@Override
public TermVector getTermVector() {
return this.termVector;
}
private void setBoost(Field field) {
/**
* MEMO from the Apache Lucene documentation:
* It is illegal to return a boost other than 1.0f for a field that is not
* indexed ({@link IndexableFieldType#indexed()} is false) or omits normalization values
* ({@link IndexableFieldType#omitNorms()} returns true).
*/
if ( indexMode.isIndexed() && ! indexMode.omitNorms() ) {
if ( documentBoostApplied == false ) {
documentBoostApplied = true;
//FIXME This isn't entirely accurate as in some cases the LuceneOptionsImpl
//is being reused for multiple fields: this needs to be significantly different,
//potentially dropping the LuceneOptionsImpl usage.
field.setBoost( fieldLevelBoost * inheritedBoost );
}
else {
field.setBoost( fieldLevelBoost );
}
}
}
private void checkNotCompressed(final String fieldName) {
//TODO this sanity check should be done at bootstrap, not runtime
if ( storeType == Store.COMPRESS ) {
throw new SearchException( "Error indexing field " + fieldName + ", @NumericField cannot be compressed" );
}
}
public void addDoubleFieldToDocument(String fieldName, double doubleValue, Document document) {
checkNotCompressed( fieldName );
DoubleField field = new DoubleField( fieldName, doubleValue, storeType != Store.NO ? Field.Store.YES : Field.Store.NO );
setBoost( field );
document.add( field );
}
public void addFloatFieldToDocument(String fieldName, float floatValue, Document document) {
checkNotCompressed( fieldName );
FloatField field = new FloatField( fieldName, floatValue, storeType != Store.NO ? Field.Store.YES : Field.Store.NO );
setBoost( field );
document.add( field );
}
public void addIntFieldToDocument(String fieldName, int intValue, Document document) {
checkNotCompressed( fieldName );
IntField field = new IntField( fieldName, intValue, storeType != Store.NO ? Field.Store.YES : Field.Store.NO );
setBoost( field );
document.add( field );
}
public void addLongFieldToDocument(String fieldName, long longValue, Document document) {
checkNotCompressed( fieldName );
LongField field = new LongField( fieldName, longValue, storeType != Store.NO ? Field.Store.YES : Field.Store.NO );
setBoost( field );
document.add( field );
}
@Override
public void addNumericFieldToDocument(String fieldName, Object indexedValue, Document document) {
if ( indexedValue == null ) {
throw new IllegalArgumentException( "the indexedValue parameter shall not be null" );
}
if ( indexedValue instanceof Double ) {
addDoubleFieldToDocument( fieldName, ( (Double) indexedValue ).doubleValue(), document );
}
else if ( indexedValue instanceof Float ) {
addFloatFieldToDocument( fieldName, ( (Float) indexedValue ).floatValue(), document );
}
else if ( indexedValue instanceof Integer ) {
addIntFieldToDocument( fieldName, ( (Integer) indexedValue ).intValue(), document );
}
else if ( indexedValue instanceof Long ) {
addLongFieldToDocument( fieldName, ( (Long) indexedValue ).longValue(), document );
}
else {
throw new IllegalArgumentException( "unsupported type of Number" );
}
}
@Override
public void addSortedDocValuesFieldToDocument(String fieldName, String indexedString, Document document) {
if ( indexedString != null ) {
document.add( new SortedDocValuesField( fieldName, new BytesRef( indexedString ) ) );
}
}
@Override
public void addNumericDocValuesFieldToDocument(String fieldName, Number numericValue, Document document) {
if ( numericValue == null ) {
throw new IllegalArgumentException( "the numericValue parameter shall not be null" );
}
if ( numericValue instanceof Double ) {
document.add( new DoubleDocValuesField( fieldName, ( (Double) numericValue ).doubleValue() ) );
}
else if ( numericValue instanceof Float ) {
document.add( new FloatDocValuesField( fieldName, ( (Float) numericValue ).floatValue() ) );
}
else if ( numericValue instanceof Integer ) {
document.add( new NumericDocValuesField( fieldName, ( (Integer) numericValue ).longValue() ) );
}
else if ( numericValue instanceof Long ) {
document.add( new NumericDocValuesField( fieldName, ( (Long) numericValue ).longValue() ) );
}
else {
throw new IllegalArgumentException( "unsupported type of Number" );
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy