-
Notifications
You must be signed in to change notification settings - Fork 242
/
LuceneStringIndexSchemaFieldContextImpl.java
163 lines (139 loc) · 6.52 KB
/
LuceneStringIndexSchemaFieldContextImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.backend.lucene.types.dsl.impl;
import java.lang.invoke.MethodHandles;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.util.QueryBuilder;
import org.hibernate.search.backend.lucene.analysis.model.impl.LuceneAnalysisDefinitionRegistry;
import org.hibernate.search.backend.lucene.document.impl.LuceneIndexFieldAccessor;
import org.hibernate.search.backend.lucene.document.model.dsl.impl.LuceneIndexSchemaContext;
import org.hibernate.search.backend.lucene.document.model.impl.LuceneIndexSchemaFieldNode;
import org.hibernate.search.backend.lucene.document.model.impl.LuceneIndexSchemaNodeCollector;
import org.hibernate.search.backend.lucene.document.model.impl.LuceneIndexSchemaObjectNode;
import org.hibernate.search.backend.lucene.logging.impl.Log;
import org.hibernate.search.backend.lucene.types.codec.impl.StringFieldCodec;
import org.hibernate.search.backend.lucene.types.converter.impl.StringFieldConverter;
import org.hibernate.search.backend.lucene.types.predicate.impl.LuceneStringFieldPredicateBuilderFactory;
import org.hibernate.search.backend.lucene.types.projection.impl.StandardFieldProjectionBuilderFactory;
import org.hibernate.search.backend.lucene.types.sort.impl.LuceneStringFieldSortBuilderFactory;
import org.hibernate.search.engine.backend.document.model.dsl.Sortable;
import org.hibernate.search.engine.backend.document.model.dsl.StringIndexSchemaFieldTypedContext;
import org.hibernate.search.engine.backend.document.spi.IndexSchemaFieldDefinitionHelper;
import org.hibernate.search.util.impl.common.LoggerFactory;
/**
* @author Guillaume Smet
*/
public class LuceneStringIndexSchemaFieldContextImpl
extends AbstractLuceneStandardIndexSchemaFieldTypedContext<LuceneStringIndexSchemaFieldContextImpl, String>
implements StringIndexSchemaFieldTypedContext<LuceneStringIndexSchemaFieldContextImpl> {
private static final Log log = LoggerFactory.make( Log.class, MethodHandles.lookup() );
private String analyzerName;
private Analyzer analyzer;
private String normalizerName;
private Analyzer normalizer;
private Sortable sortable = Sortable.DEFAULT;
public LuceneStringIndexSchemaFieldContextImpl(LuceneIndexSchemaContext schemaContext, String relativeFieldName) {
super( schemaContext, relativeFieldName, String.class );
}
@Override
public LuceneStringIndexSchemaFieldContextImpl analyzer(String analyzerName) {
this.analyzerName = analyzerName;
this.analyzer = getAnalysisDefinitionRegistry().getAnalyzerDefinition( analyzerName );
if ( analyzer == null ) {
throw log.unknownAnalyzer( analyzerName, getSchemaContext().getEventContext() );
}
return this;
}
@Override
public LuceneStringIndexSchemaFieldContextImpl normalizer(String normalizerName) {
this.normalizerName = normalizerName;
this.normalizer = getAnalysisDefinitionRegistry().getNormalizerDefinition( normalizerName );
if ( normalizer == null ) {
throw log.unknownNormalizer( normalizerName, getSchemaContext().getEventContext() );
}
return this;
}
@Override
public LuceneStringIndexSchemaFieldContextImpl sortable(Sortable sortable) {
this.sortable = sortable;
return this;
}
@Override
protected void contribute(IndexSchemaFieldDefinitionHelper<String> helper, LuceneIndexSchemaNodeCollector collector,
LuceneIndexSchemaObjectNode parentNode) {
boolean resolvedSortable = resolveDefault( sortable );
boolean resolvedProjectable = resolveDefault( projectable );
if ( analyzer != null ) {
if ( resolvedSortable ) {
throw log.cannotUseAnalyzerOnSortableField( analyzerName, getSchemaContext().getEventContext() );
}
if ( normalizer != null ) {
throw log.cannotApplyAnalyzerAndNormalizer( analyzerName, normalizerName, getSchemaContext().getEventContext() );
}
}
// TODO GSM: the idea would be to create only one global QueryBuilder object per analyzer/normalizer
Analyzer analyzerOrNormalizer = analyzer != null ? analyzer : normalizer;
QueryBuilder queryBuilder = analyzerOrNormalizer != null ? new QueryBuilder( analyzerOrNormalizer ) : null;
StringFieldConverter converter = new StringFieldConverter(
helper.createUserIndexFieldConverter(),
analyzerOrNormalizer
);
StringFieldCodec codec = new StringFieldCodec(
resolvedSortable,
getFieldType( resolvedProjectable, analyzer != null ),
analyzerOrNormalizer
);
LuceneIndexSchemaFieldNode<String> schemaNode = new LuceneIndexSchemaFieldNode<>(
parentNode,
getRelativeFieldName(),
converter,
codec,
new LuceneStringFieldPredicateBuilderFactory( converter, analyzer != null, queryBuilder ),
new LuceneStringFieldSortBuilderFactory( resolvedSortable, converter ),
new StandardFieldProjectionBuilderFactory<>( resolvedProjectable, codec, converter )
);
helper.initialize( new LuceneIndexFieldAccessor<>( schemaNode ) );
collector.collectFieldNode( schemaNode.getAbsoluteFieldPath(), schemaNode );
if ( analyzerOrNormalizer != null ) {
collector.collectAnalyzer( schemaNode.getAbsoluteFieldPath(), analyzerOrNormalizer );
}
}
@Override
protected LuceneStringIndexSchemaFieldContextImpl thisAsS() {
return this;
}
private LuceneAnalysisDefinitionRegistry getAnalysisDefinitionRegistry() {
return getSchemaContext().getRoot().getAnalysisDefinitionRegistry();
}
private static FieldType getFieldType(boolean projectable, boolean analyzed) {
FieldType fieldType = new FieldType();
if ( analyzed ) {
// TODO GSM: take into account the norms and term vectors options
fieldType.setOmitNorms( false );
fieldType.setIndexOptions( IndexOptions.DOCS_AND_FREQS_AND_POSITIONS );
fieldType.setStoreTermVectors( true );
fieldType.setStoreTermVectorPositions( true );
fieldType.setStoreTermVectorOffsets( true );
fieldType.setTokenized( true );
}
else {
fieldType.setOmitNorms( true );
fieldType.setIndexOptions( IndexOptions.DOCS );
/*
* Note that the name "tokenized" is misleading: it actually means "should the analyzer (or normalizer) be applied".
* When it's false, the analyzer/normalizer is completely ignored, not just tokenization.
* Thus it should be true even when just using a normalizer.
*/
fieldType.setTokenized( true );
}
fieldType.setStored( projectable );
fieldType.freeze();
return fieldType;
}
}