Allow to customize quote analyzer to be used when quoting text in a query_string, closes #1931.
This commit is contained in:
parent
379976b5ce
commit
acbd7b686a
|
@ -64,12 +64,17 @@ public class MapperQueryParser extends QueryParser {
|
|||
|
||||
private final QueryParseContext parseContext;
|
||||
|
||||
private Analyzer quoteAnalyzer;
|
||||
|
||||
private boolean forcedAnalyzer;
|
||||
private boolean forcedQuoteAnalyzer;
|
||||
|
||||
private FieldMapper currentMapper;
|
||||
|
||||
private boolean analyzeWildcard;
|
||||
|
||||
private String quoteFieldSuffix;
|
||||
|
||||
public MapperQueryParser(QueryParseContext parseContext) {
|
||||
super(Lucene.QUERYPARSER_VERSION, null, null);
|
||||
this.parseContext = parseContext;
|
||||
|
@ -85,6 +90,17 @@ public class MapperQueryParser extends QueryParser {
|
|||
this.field = settings.defaultField();
|
||||
this.forcedAnalyzer = settings.forcedAnalyzer() != null;
|
||||
this.analyzer = forcedAnalyzer ? settings.forcedAnalyzer() : settings.defaultAnalyzer();
|
||||
if (settings.forcedQuoteAnalyzer() != null) {
|
||||
this.forcedQuoteAnalyzer = true;
|
||||
this.quoteAnalyzer = settings.forcedQuoteAnalyzer();
|
||||
} else if (forcedAnalyzer) {
|
||||
this.forcedQuoteAnalyzer = true;
|
||||
this.quoteAnalyzer = settings.forcedAnalyzer();
|
||||
} else {
|
||||
this.forcedAnalyzer = false;
|
||||
this.quoteAnalyzer = settings.defaultQuoteAnalyzer();
|
||||
}
|
||||
this.quoteFieldSuffix = settings.quoteFieldSuffix();
|
||||
setMultiTermRewriteMethod(settings.rewriteMethod());
|
||||
setEnablePositionIncrements(settings.enablePositionIncrements());
|
||||
setAutoGeneratePhraseQueries(settings.autoGeneratePhraseQueries());
|
||||
|
@ -122,10 +138,25 @@ public class MapperQueryParser extends QueryParser {
|
|||
currentMapper = null;
|
||||
Analyzer oldAnalyzer = analyzer;
|
||||
try {
|
||||
MapperService.SmartNameFieldMappers fieldMappers = parseContext.smartFieldMappers(field);
|
||||
MapperService.SmartNameFieldMappers fieldMappers = null;
|
||||
if (quoted) {
|
||||
analyzer = quoteAnalyzer;
|
||||
if (quoteFieldSuffix != null) {
|
||||
fieldMappers = parseContext.smartFieldMappers(field + quoteFieldSuffix);
|
||||
}
|
||||
}
|
||||
if (fieldMappers == null) {
|
||||
fieldMappers = parseContext.smartFieldMappers(field);
|
||||
}
|
||||
if (fieldMappers != null) {
|
||||
if (!forcedAnalyzer) {
|
||||
analyzer = fieldMappers.searchAnalyzer();
|
||||
if (quoted) {
|
||||
if (!forcedQuoteAnalyzer) {
|
||||
analyzer = fieldMappers.searchQuoteAnalyzer();
|
||||
}
|
||||
} else {
|
||||
if (!forcedAnalyzer) {
|
||||
analyzer = fieldMappers.searchAnalyzer();
|
||||
}
|
||||
}
|
||||
currentMapper = fieldMappers.fieldMappers().mapper();
|
||||
if (currentMapper != null) {
|
||||
|
|
|
@ -45,7 +45,10 @@ public class QueryParserSettings {
|
|||
private boolean analyzeWildcard = DEFAULT_ANALYZE_WILDCARD;
|
||||
private boolean escape = false;
|
||||
private Analyzer defaultAnalyzer = null;
|
||||
private Analyzer defaultQuoteAnalyzer = null;
|
||||
private Analyzer forcedAnalyzer = null;
|
||||
private Analyzer forcedQuoteAnalyzer = null;
|
||||
private String quoteFieldSuffix = null;
|
||||
private MultiTermQuery.RewriteMethod rewriteMethod = MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT;
|
||||
private String minimumShouldMatch;
|
||||
|
||||
|
@ -153,6 +156,14 @@ public class QueryParserSettings {
|
|||
this.defaultAnalyzer = defaultAnalyzer;
|
||||
}
|
||||
|
||||
public Analyzer defaultQuoteAnalyzer() {
|
||||
return defaultQuoteAnalyzer;
|
||||
}
|
||||
|
||||
public void defaultQuoteAnalyzer(Analyzer defaultAnalyzer) {
|
||||
this.defaultQuoteAnalyzer = defaultAnalyzer;
|
||||
}
|
||||
|
||||
public Analyzer forcedAnalyzer() {
|
||||
return forcedAnalyzer;
|
||||
}
|
||||
|
@ -161,6 +172,14 @@ public class QueryParserSettings {
|
|||
this.forcedAnalyzer = forcedAnalyzer;
|
||||
}
|
||||
|
||||
public Analyzer forcedQuoteAnalyzer() {
|
||||
return forcedQuoteAnalyzer;
|
||||
}
|
||||
|
||||
public void forcedQuoteAnalyzer(Analyzer forcedAnalyzer) {
|
||||
this.forcedQuoteAnalyzer = forcedAnalyzer;
|
||||
}
|
||||
|
||||
public boolean analyzeWildcard() {
|
||||
return this.analyzeWildcard;
|
||||
}
|
||||
|
@ -185,6 +204,14 @@ public class QueryParserSettings {
|
|||
this.minimumShouldMatch = minimumShouldMatch;
|
||||
}
|
||||
|
||||
public void quoteFieldSuffix(String quoteFieldSuffix) {
|
||||
this.quoteFieldSuffix = quoteFieldSuffix;
|
||||
}
|
||||
|
||||
public String quoteFieldSuffix() {
|
||||
return this.quoteFieldSuffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -204,8 +231,12 @@ public class QueryParserSettings {
|
|||
if (phraseSlop != that.phraseSlop) return false;
|
||||
if (defaultAnalyzer != null ? !defaultAnalyzer.equals(that.defaultAnalyzer) : that.defaultAnalyzer != null)
|
||||
return false;
|
||||
if (defaultQuoteAnalyzer != null ? !defaultQuoteAnalyzer.equals(that.defaultQuoteAnalyzer) : that.defaultQuoteAnalyzer != null)
|
||||
return false;
|
||||
if (forcedAnalyzer != null ? !forcedAnalyzer.equals(that.forcedAnalyzer) : that.forcedAnalyzer != null)
|
||||
return false;
|
||||
if (forcedQuoteAnalyzer != null ? !forcedQuoteAnalyzer.equals(that.forcedQuoteAnalyzer) : that.forcedQuoteAnalyzer != null)
|
||||
return false;
|
||||
if (defaultField != null ? !defaultField.equals(that.defaultField) : that.defaultField != null) return false;
|
||||
if (defaultOperator != that.defaultOperator) return false;
|
||||
if (queryString != null ? !queryString.equals(that.queryString) : that.queryString != null) return false;
|
||||
|
@ -213,6 +244,8 @@ public class QueryParserSettings {
|
|||
return false;
|
||||
if (minimumShouldMatch != null ? !minimumShouldMatch.equals(that.minimumShouldMatch) : that.minimumShouldMatch != null)
|
||||
return false;
|
||||
if (quoteFieldSuffix != null ? !quoteFieldSuffix.equals(that.quoteFieldSuffix) : that.quoteFieldSuffix != null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -232,7 +265,9 @@ public class QueryParserSettings {
|
|||
result = 31 * result + fuzzyPrefixLength;
|
||||
result = 31 * result + (escape ? 1 : 0);
|
||||
result = 31 * result + (defaultAnalyzer != null ? defaultAnalyzer.hashCode() : 0);
|
||||
result = 31 * result + (defaultQuoteAnalyzer != null ? defaultQuoteAnalyzer.hashCode() : 0);
|
||||
result = 31 * result + (forcedAnalyzer != null ? forcedAnalyzer.hashCode() : 0);
|
||||
result = 31 * result + (forcedQuoteAnalyzer != null ? forcedQuoteAnalyzer.hashCode() : 0);
|
||||
result = 31 * result + (analyzeWildcard ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ public class AnalysisService extends AbstractIndexComponent implements Closeable
|
|||
private final NamedAnalyzer defaultAnalyzer;
|
||||
private final NamedAnalyzer defaultIndexAnalyzer;
|
||||
private final NamedAnalyzer defaultSearchAnalyzer;
|
||||
private final NamedAnalyzer defaultSearchQuoteAnalyzer;
|
||||
|
||||
public AnalysisService(Index index) {
|
||||
this(index, ImmutableSettings.Builder.EMPTY_SETTINGS, null, null, null, null, null);
|
||||
|
@ -209,6 +210,9 @@ public class AnalysisService extends AbstractIndexComponent implements Closeable
|
|||
if (!analyzerProviders.containsKey("default_search")) {
|
||||
analyzerProviders.put("default_search", analyzerProviders.get("default"));
|
||||
}
|
||||
if (!analyzerProviders.containsKey("default_search_quoted")) {
|
||||
analyzerProviders.put("default_search_quoted", analyzerProviders.get("default_search"));
|
||||
}
|
||||
|
||||
Map<String, NamedAnalyzer> analyzers = newHashMap();
|
||||
for (AnalyzerProvider analyzerFactory : analyzerProviders.values()) {
|
||||
|
@ -233,6 +237,7 @@ public class AnalysisService extends AbstractIndexComponent implements Closeable
|
|||
defaultAnalyzer = analyzers.get("default");
|
||||
defaultIndexAnalyzer = analyzers.containsKey("default_index") ? analyzers.get("default_index") : analyzers.get("default");
|
||||
defaultSearchAnalyzer = analyzers.containsKey("default_search") ? analyzers.get("default_search") : analyzers.get("default");
|
||||
defaultSearchQuoteAnalyzer = analyzers.containsKey("default_search_quote") ? analyzers.get("default_search_quote") : defaultSearchAnalyzer;
|
||||
|
||||
this.analyzers = ImmutableMap.copyOf(analyzers);
|
||||
}
|
||||
|
@ -268,6 +273,10 @@ public class AnalysisService extends AbstractIndexComponent implements Closeable
|
|||
return defaultSearchAnalyzer;
|
||||
}
|
||||
|
||||
public NamedAnalyzer defaultSearchQuoteAnalyzer() {
|
||||
return defaultSearchQuoteAnalyzer;
|
||||
}
|
||||
|
||||
public TokenizerFactory tokenizer(String name) {
|
||||
return tokenizers.get(name);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ public class DocumentFieldMappers implements Iterable<FieldMapper> {
|
|||
|
||||
private final FieldNameAnalyzer indexAnalyzer;
|
||||
private final FieldNameAnalyzer searchAnalyzer;
|
||||
private final FieldNameAnalyzer searchQuoteAnalyzer;
|
||||
|
||||
public DocumentFieldMappers(DocumentMapper docMapper, Iterable<FieldMapper> fieldMappers) {
|
||||
final Map<String, FieldMappers> tempNameFieldMappers = newHashMap();
|
||||
|
@ -50,6 +51,7 @@ public class DocumentFieldMappers implements Iterable<FieldMapper> {
|
|||
|
||||
final Map<String, Analyzer> indexAnalyzers = newHashMap();
|
||||
final Map<String, Analyzer> searchAnalyzers = newHashMap();
|
||||
final Map<String, Analyzer> searchQuoteAnalyzers = newHashMap();
|
||||
|
||||
for (FieldMapper fieldMapper : fieldMappers) {
|
||||
FieldMappers mappers = tempNameFieldMappers.get(fieldMapper.names().name());
|
||||
|
@ -82,6 +84,9 @@ public class DocumentFieldMappers implements Iterable<FieldMapper> {
|
|||
if (fieldMapper.searchAnalyzer() != null) {
|
||||
searchAnalyzers.put(fieldMapper.names().indexName(), fieldMapper.searchAnalyzer());
|
||||
}
|
||||
if (fieldMapper.searchQuoteAnalyzer() != null) {
|
||||
searchQuoteAnalyzers.put(fieldMapper.names().indexName(), fieldMapper.searchQuoteAnalyzer());
|
||||
}
|
||||
}
|
||||
this.fieldMappers = ImmutableList.copyOf(fieldMappers);
|
||||
this.nameFieldMappers = ImmutableMap.copyOf(tempNameFieldMappers);
|
||||
|
@ -90,6 +95,7 @@ public class DocumentFieldMappers implements Iterable<FieldMapper> {
|
|||
|
||||
this.indexAnalyzer = new FieldNameAnalyzer(indexAnalyzers, docMapper.indexAnalyzer());
|
||||
this.searchAnalyzer = new FieldNameAnalyzer(searchAnalyzers, docMapper.searchAnalyzer());
|
||||
this.searchQuoteAnalyzer = new FieldNameAnalyzer(searchQuoteAnalyzers, docMapper.searchQuotedAnalyzer());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -179,6 +185,10 @@ public class DocumentFieldMappers implements Iterable<FieldMapper> {
|
|||
return this.searchAnalyzer;
|
||||
}
|
||||
|
||||
public Analyzer searchQuoteAnalyzer() {
|
||||
return this.searchQuoteAnalyzer;
|
||||
}
|
||||
|
||||
public DocumentFieldMappers concat(DocumentMapper docMapper, FieldMapper... fieldMappers) {
|
||||
return concat(docMapper, newArrayList(fieldMappers));
|
||||
}
|
||||
|
|
|
@ -132,6 +132,8 @@ public class DocumentMapper implements ToXContent {
|
|||
|
||||
private NamedAnalyzer searchAnalyzer;
|
||||
|
||||
private NamedAnalyzer searchQuoteAnalyzer;
|
||||
|
||||
private final String index;
|
||||
|
||||
@Nullable
|
||||
|
@ -193,6 +195,14 @@ public class DocumentMapper implements ToXContent {
|
|||
|
||||
public Builder searchAnalyzer(NamedAnalyzer searchAnalyzer) {
|
||||
this.searchAnalyzer = searchAnalyzer;
|
||||
if (this.searchQuoteAnalyzer == null) {
|
||||
this.searchQuoteAnalyzer = searchAnalyzer;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder searchQuoteAnalyzer(NamedAnalyzer searchQuoteAnalyzer) {
|
||||
this.searchQuoteAnalyzer = searchQuoteAnalyzer;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -200,10 +210,14 @@ public class DocumentMapper implements ToXContent {
|
|||
return searchAnalyzer != null;
|
||||
}
|
||||
|
||||
public boolean hasSearchQuoteAnalyzer() {
|
||||
return searchQuoteAnalyzer != null;
|
||||
}
|
||||
|
||||
public DocumentMapper build(DocumentMapperParser docMapperParser) {
|
||||
Preconditions.checkNotNull(rootObjectMapper, "Mapper builder must have the root object mapper set");
|
||||
return new DocumentMapper(index, indexSettings, docMapperParser, rootObjectMapper, meta,
|
||||
indexAnalyzer, searchAnalyzer,
|
||||
indexAnalyzer, searchAnalyzer, searchQuoteAnalyzer,
|
||||
rootMappers);
|
||||
}
|
||||
}
|
||||
|
@ -237,6 +251,7 @@ public class DocumentMapper implements ToXContent {
|
|||
private final NamedAnalyzer indexAnalyzer;
|
||||
|
||||
private final NamedAnalyzer searchAnalyzer;
|
||||
private final NamedAnalyzer searchQuoteAnalyzer;
|
||||
|
||||
private volatile DocumentFieldMappers fieldMappers;
|
||||
|
||||
|
@ -257,7 +272,7 @@ public class DocumentMapper implements ToXContent {
|
|||
public DocumentMapper(String index, @Nullable Settings indexSettings, DocumentMapperParser docMapperParser,
|
||||
RootObjectMapper rootObjectMapper,
|
||||
ImmutableMap<String, Object> meta,
|
||||
NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer,
|
||||
NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer, NamedAnalyzer searchQuoteAnalyzer,
|
||||
Map<Class<? extends RootMapper>, RootMapper> rootMappers) {
|
||||
this.index = index;
|
||||
this.indexSettings = indexSettings;
|
||||
|
@ -278,6 +293,7 @@ public class DocumentMapper implements ToXContent {
|
|||
|
||||
this.indexAnalyzer = indexAnalyzer;
|
||||
this.searchAnalyzer = searchAnalyzer;
|
||||
this.searchQuoteAnalyzer = searchQuoteAnalyzer != null ? searchQuoteAnalyzer : searchAnalyzer;
|
||||
|
||||
this.typeFilter = typeMapper().fieldFilter(type, null);
|
||||
|
||||
|
@ -389,6 +405,10 @@ public class DocumentMapper implements ToXContent {
|
|||
return this.searchAnalyzer;
|
||||
}
|
||||
|
||||
public Analyzer searchQuotedAnalyzer() {
|
||||
return this.searchQuoteAnalyzer;
|
||||
}
|
||||
|
||||
public Filter typeFilter() {
|
||||
return this.typeFilter;
|
||||
}
|
||||
|
|
|
@ -177,6 +177,12 @@ public class DocumentMapperParser extends AbstractIndexComponent {
|
|||
throw new MapperParsingException("Analyzer [" + fieldNode.toString() + "] not found for search_analyzer setting on root type [" + type + "]");
|
||||
}
|
||||
docBuilder.searchAnalyzer(analyzer);
|
||||
} else if ("search_quote_analyzer".equals(fieldName)) {
|
||||
NamedAnalyzer analyzer = analysisService.analyzer(fieldNode.toString());
|
||||
if (analyzer == null) {
|
||||
throw new MapperParsingException("Analyzer [" + fieldNode.toString() + "] not found for search_analyzer setting on root type [" + type + "]");
|
||||
}
|
||||
docBuilder.searchQuoteAnalyzer(analyzer);
|
||||
} else if ("analyzer".equals(fieldName)) {
|
||||
NamedAnalyzer analyzer = analysisService.analyzer(fieldNode.toString());
|
||||
if (analyzer == null) {
|
||||
|
@ -198,6 +204,9 @@ public class DocumentMapperParser extends AbstractIndexComponent {
|
|||
if (!docBuilder.hasSearchAnalyzer()) {
|
||||
docBuilder.searchAnalyzer(analysisService.defaultSearchAnalyzer());
|
||||
}
|
||||
if (!docBuilder.hasSearchQuoteAnalyzer()) {
|
||||
docBuilder.searchAnalyzer(analysisService.defaultSearchQuoteAnalyzer());
|
||||
}
|
||||
|
||||
ImmutableMap<String, Object> attributes = ImmutableMap.of();
|
||||
if (mapping.containsKey("_meta")) {
|
||||
|
|
|
@ -147,6 +147,11 @@ public interface FieldMapper<T> {
|
|||
*/
|
||||
Analyzer searchAnalyzer();
|
||||
|
||||
/**
|
||||
* The analyzer that will be used for quoted search on the field.
|
||||
*/
|
||||
Analyzer searchQuoteAnalyzer();
|
||||
|
||||
/**
|
||||
* Returns the value that will be used as a result for search. Can be only of specific types... .
|
||||
*/
|
||||
|
|
|
@ -95,6 +95,7 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
|
|||
private final InternalObjectMapperListener objectMapperListener = new InternalObjectMapperListener();
|
||||
|
||||
private final SmartIndexNameSearchAnalyzer searchAnalyzer;
|
||||
private final SmartIndexNameSearchQuoteAnalyzer searchQuoteAnalyzer;
|
||||
|
||||
@Inject
|
||||
public MapperService(Index index, @IndexSettings Settings indexSettings, Environment environment, AnalysisService analysisService) {
|
||||
|
@ -102,6 +103,7 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
|
|||
this.analysisService = analysisService;
|
||||
this.documentParser = new DocumentMapperParser(index, indexSettings, analysisService);
|
||||
this.searchAnalyzer = new SmartIndexNameSearchAnalyzer(analysisService.defaultSearchAnalyzer());
|
||||
this.searchQuoteAnalyzer = new SmartIndexNameSearchQuoteAnalyzer(analysisService.defaultSearchQuoteAnalyzer());
|
||||
|
||||
this.dynamic = componentSettings.getAsBoolean("dynamic", true);
|
||||
String defaultMappingLocation = componentSettings.get("default_mapping_location");
|
||||
|
@ -665,6 +667,10 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
|
|||
return this.searchAnalyzer;
|
||||
}
|
||||
|
||||
public Analyzer searchQuoteAnalyzer() {
|
||||
return this.searchQuoteAnalyzer;
|
||||
}
|
||||
|
||||
public static class SmartNameObjectMapper {
|
||||
private final ObjectMapper mapper;
|
||||
private final DocumentMapper docMapper;
|
||||
|
@ -767,6 +773,19 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
|
|||
}
|
||||
return mapperService.searchAnalyzer();
|
||||
}
|
||||
|
||||
public Analyzer searchQuoteAnalyzer() {
|
||||
if (hasMapper()) {
|
||||
Analyzer analyzer = mapper().searchQuoteAnalyzer();
|
||||
if (analyzer != null) {
|
||||
return analyzer;
|
||||
}
|
||||
}
|
||||
if (docMapper != null && docMapper.searchQuotedAnalyzer() != null) {
|
||||
return docMapper.searchQuotedAnalyzer();
|
||||
}
|
||||
return mapperService.searchQuoteAnalyzer();
|
||||
}
|
||||
}
|
||||
|
||||
final class SmartIndexNameSearchAnalyzer extends Analyzer {
|
||||
|
@ -867,6 +886,104 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
|
|||
}
|
||||
}
|
||||
|
||||
final class SmartIndexNameSearchQuoteAnalyzer extends Analyzer {
|
||||
|
||||
private final Analyzer defaultAnalyzer;
|
||||
|
||||
SmartIndexNameSearchQuoteAnalyzer(Analyzer defaultAnalyzer) {
|
||||
this.defaultAnalyzer = defaultAnalyzer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPositionIncrementGap(String fieldName) {
|
||||
int dotIndex = fieldName.indexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
String possibleType = fieldName.substring(0, dotIndex);
|
||||
DocumentMapper possibleDocMapper = mappers.get(possibleType);
|
||||
if (possibleDocMapper != null) {
|
||||
return possibleDocMapper.mappers().searchQuoteAnalyzer().getPositionIncrementGap(fieldName);
|
||||
}
|
||||
}
|
||||
FieldMappers mappers = fullNameFieldMappers.get(fieldName);
|
||||
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchAnalyzer() != null) {
|
||||
return mappers.mapper().searchQuoteAnalyzer().getPositionIncrementGap(fieldName);
|
||||
}
|
||||
|
||||
mappers = indexNameFieldMappers.get(fieldName);
|
||||
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchAnalyzer() != null) {
|
||||
return mappers.mapper().searchQuoteAnalyzer().getPositionIncrementGap(fieldName);
|
||||
}
|
||||
return defaultAnalyzer.getPositionIncrementGap(fieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffsetGap(Fieldable field) {
|
||||
String fieldName = field.name();
|
||||
int dotIndex = fieldName.indexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
String possibleType = fieldName.substring(0, dotIndex);
|
||||
DocumentMapper possibleDocMapper = mappers.get(possibleType);
|
||||
if (possibleDocMapper != null) {
|
||||
return possibleDocMapper.mappers().searchQuoteAnalyzer().getOffsetGap(field);
|
||||
}
|
||||
}
|
||||
FieldMappers mappers = fullNameFieldMappers.get(fieldName);
|
||||
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchAnalyzer() != null) {
|
||||
return mappers.mapper().searchQuoteAnalyzer().getOffsetGap(field);
|
||||
}
|
||||
|
||||
mappers = indexNameFieldMappers.get(fieldName);
|
||||
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchAnalyzer() != null) {
|
||||
return mappers.mapper().searchQuoteAnalyzer().getOffsetGap(field);
|
||||
}
|
||||
return defaultAnalyzer.getOffsetGap(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final TokenStream tokenStream(String fieldName, Reader reader) {
|
||||
int dotIndex = fieldName.indexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
String possibleType = fieldName.substring(0, dotIndex);
|
||||
DocumentMapper possibleDocMapper = mappers.get(possibleType);
|
||||
if (possibleDocMapper != null) {
|
||||
return possibleDocMapper.mappers().searchQuoteAnalyzer().tokenStream(fieldName, reader);
|
||||
}
|
||||
}
|
||||
FieldMappers mappers = fullNameFieldMappers.get(fieldName);
|
||||
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchAnalyzer() != null) {
|
||||
return mappers.mapper().searchQuoteAnalyzer().tokenStream(fieldName, reader);
|
||||
}
|
||||
|
||||
mappers = indexNameFieldMappers.get(fieldName);
|
||||
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchAnalyzer() != null) {
|
||||
return mappers.mapper().searchQuoteAnalyzer().tokenStream(fieldName, reader);
|
||||
}
|
||||
return defaultAnalyzer.tokenStream(fieldName, reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final TokenStream reusableTokenStream(String fieldName, Reader reader) throws IOException {
|
||||
int dotIndex = fieldName.indexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
String possibleType = fieldName.substring(0, dotIndex);
|
||||
DocumentMapper possibleDocMapper = mappers.get(possibleType);
|
||||
if (possibleDocMapper != null) {
|
||||
return possibleDocMapper.mappers().searchQuoteAnalyzer().reusableTokenStream(fieldName, reader);
|
||||
}
|
||||
}
|
||||
FieldMappers mappers = fullNameFieldMappers.get(fieldName);
|
||||
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchAnalyzer() != null) {
|
||||
return mappers.mapper().searchQuoteAnalyzer().reusableTokenStream(fieldName, reader);
|
||||
}
|
||||
|
||||
mappers = indexNameFieldMappers.get(fieldName);
|
||||
if (mappers != null && mappers.mapper() != null && mappers.mapper().searchAnalyzer() != null) {
|
||||
return mappers.mapper().searchQuoteAnalyzer().reusableTokenStream(fieldName, reader);
|
||||
}
|
||||
return defaultAnalyzer.reusableTokenStream(fieldName, reader);
|
||||
}
|
||||
}
|
||||
|
||||
class InternalFieldMapperListener implements FieldMapperListener {
|
||||
@Override
|
||||
public void fieldMapper(FieldMapper fieldMapper) {
|
||||
|
|
|
@ -301,6 +301,11 @@ public abstract class AbstractFieldMapper<T> implements FieldMapper<T>, Mapper {
|
|||
return this.searchAnalyzer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Analyzer searchQuoteAnalyzer() {
|
||||
return this.searchAnalyzer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parse(ParseContext context) throws IOException {
|
||||
try {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.elasticsearch.index.mapper.core;
|
||||
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.Fieldable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
|
@ -55,6 +56,8 @@ public class StringFieldMapper extends AbstractFieldMapper<String> implements Al
|
|||
|
||||
protected int positionOffsetGap = Defaults.POSITION_OFFSET_GAP;
|
||||
|
||||
protected NamedAnalyzer searchQuotedAnalyzer;
|
||||
|
||||
public Builder(String name) {
|
||||
super(name);
|
||||
builder = this;
|
||||
|
@ -71,20 +74,35 @@ public class StringFieldMapper extends AbstractFieldMapper<String> implements Al
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder searchAnalyzer(NamedAnalyzer searchAnalyzer) {
|
||||
super.searchAnalyzer(searchAnalyzer);
|
||||
if (searchQuotedAnalyzer == null) {
|
||||
searchQuotedAnalyzer = searchAnalyzer;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder positionOffsetGap(int positionOffsetGap) {
|
||||
this.positionOffsetGap = positionOffsetGap;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder searchQuotedAnalyzer(NamedAnalyzer analyzer) {
|
||||
this.searchQuotedAnalyzer = analyzer;
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringFieldMapper build(BuilderContext context) {
|
||||
if (positionOffsetGap > 0) {
|
||||
indexAnalyzer = new NamedCustomAnalyzer(indexAnalyzer, positionOffsetGap);
|
||||
searchAnalyzer = new NamedCustomAnalyzer(searchAnalyzer, positionOffsetGap);
|
||||
searchQuotedAnalyzer = new NamedCustomAnalyzer(searchQuotedAnalyzer, positionOffsetGap);
|
||||
}
|
||||
StringFieldMapper fieldMapper = new StringFieldMapper(buildNames(context),
|
||||
index, store, termVector, boost, omitNorms, omitTermFreqAndPositions, nullValue,
|
||||
indexAnalyzer, searchAnalyzer, positionOffsetGap);
|
||||
indexAnalyzer, searchAnalyzer, searchQuotedAnalyzer, positionOffsetGap);
|
||||
fieldMapper.includeInAll(includeInAll);
|
||||
return fieldMapper;
|
||||
}
|
||||
|
@ -100,6 +118,12 @@ public class StringFieldMapper extends AbstractFieldMapper<String> implements Al
|
|||
Object propNode = entry.getValue();
|
||||
if (propName.equals("null_value")) {
|
||||
builder.nullValue(propNode.toString());
|
||||
} else if (propName.equals("search_quote_analyzer")) {
|
||||
NamedAnalyzer analyzer = parserContext.analysisService().analyzer(propNode.toString());
|
||||
if (analyzer == null) {
|
||||
throw new MapperParsingException("Analyzer [" + propNode.toString() + "] not found for field [" + name + "]");
|
||||
}
|
||||
builder.searchQuotedAnalyzer(analyzer);
|
||||
} else if (propName.equals("position_offset_gap")) {
|
||||
builder.positionOffsetGap(XContentMapValues.nodeIntegerValue(propNode, -1));
|
||||
// we need to update to actual analyzers if they are not set in this case...
|
||||
|
@ -110,6 +134,9 @@ public class StringFieldMapper extends AbstractFieldMapper<String> implements Al
|
|||
if (builder.searchAnalyzer == null) {
|
||||
builder.searchAnalyzer = parserContext.analysisService().defaultSearchAnalyzer();
|
||||
}
|
||||
if (builder.searchQuotedAnalyzer == null) {
|
||||
builder.searchQuotedAnalyzer = parserContext.analysisService().defaultSearchQuoteAnalyzer();
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
|
@ -122,18 +149,21 @@ public class StringFieldMapper extends AbstractFieldMapper<String> implements Al
|
|||
|
||||
private int positionOffsetGap;
|
||||
|
||||
private NamedAnalyzer searchQuotedAnalyzer;
|
||||
|
||||
protected StringFieldMapper(Names names, Field.Index index, Field.Store store, Field.TermVector termVector,
|
||||
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
|
||||
String nullValue, NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer) {
|
||||
this(names, index, store, termVector, boost, omitNorms, omitTermFreqAndPositions, nullValue, indexAnalyzer, searchAnalyzer, Defaults.POSITION_OFFSET_GAP);
|
||||
this(names, index, store, termVector, boost, omitNorms, omitTermFreqAndPositions, nullValue, indexAnalyzer, searchAnalyzer, searchAnalyzer, Defaults.POSITION_OFFSET_GAP);
|
||||
}
|
||||
|
||||
protected StringFieldMapper(Names names, Field.Index index, Field.Store store, Field.TermVector termVector,
|
||||
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
|
||||
String nullValue, NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer, int positionOffsetGap) {
|
||||
String nullValue, NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer, NamedAnalyzer searchQuotedAnalyzer, int positionOffsetGap) {
|
||||
super(names, index, store, termVector, boost, omitNorms, omitTermFreqAndPositions, indexAnalyzer, searchAnalyzer);
|
||||
this.nullValue = nullValue;
|
||||
this.positionOffsetGap = positionOffsetGap;
|
||||
this.searchQuotedAnalyzer = searchQuotedAnalyzer != null ? searchQuotedAnalyzer : searchAnalyzer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -179,6 +209,11 @@ public class StringFieldMapper extends AbstractFieldMapper<String> implements Al
|
|||
return this.positionOffsetGap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Analyzer searchQuoteAnalyzer() {
|
||||
return this.searchQuotedAnalyzer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Field parseCreateField(ParseContext context) throws IOException {
|
||||
String value = nullValue;
|
||||
|
@ -266,5 +301,8 @@ public class StringFieldMapper extends AbstractFieldMapper<String> implements Al
|
|||
if (positionOffsetGap != Defaults.POSITION_OFFSET_GAP) {
|
||||
builder.field("position_offset_gap", positionOffsetGap);
|
||||
}
|
||||
if (searchQuotedAnalyzer != null && searchAnalyzer != searchQuotedAnalyzer) {
|
||||
builder.field("search_quote_analyzer", searchQuotedAnalyzer.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,12 @@ public class FieldQueryParser implements QueryParser {
|
|||
throw new QueryParsingException(parseContext.index(), "[query_string] analyzer [" + parser.text() + "] not found");
|
||||
}
|
||||
qpSettings.forcedAnalyzer(analyzer);
|
||||
} else if ("quote_analyzer".equals(currentFieldName) || "quoteAnalyzer".equals(currentFieldName)) {
|
||||
NamedAnalyzer analyzer = parseContext.analysisService().analyzer(parser.text());
|
||||
if (analyzer == null) {
|
||||
throw new QueryParsingException(parseContext.index(), "[query_string] analyzer [" + parser.text() + "] not found");
|
||||
}
|
||||
qpSettings.forcedQuoteAnalyzer(analyzer);
|
||||
} else if ("default_operator".equals(currentFieldName) || "defaultOperator".equals(currentFieldName)) {
|
||||
String op = parser.text();
|
||||
if ("or".equalsIgnoreCase(op)) {
|
||||
|
@ -120,6 +126,8 @@ public class FieldQueryParser implements QueryParser {
|
|||
qpSettings.rewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull()));
|
||||
} else if ("minimum_should_match".equals(currentFieldName) || "minimumShouldMatch".equals(currentFieldName)) {
|
||||
qpSettings.minimumShouldMatch(parser.textOrNull());
|
||||
} else if ("quote_field_suffix".equals(currentFieldName) || "quoteFieldSuffix".equals(currentFieldName)) {
|
||||
qpSettings.quoteFieldSuffix(parser.textOrNull());
|
||||
} else {
|
||||
throw new QueryParsingException(parseContext.index(), "[field] query does not support [" + currentFieldName + "]");
|
||||
}
|
||||
|
@ -133,6 +141,7 @@ public class FieldQueryParser implements QueryParser {
|
|||
}
|
||||
|
||||
qpSettings.defaultAnalyzer(parseContext.mapperService().searchAnalyzer());
|
||||
qpSettings.defaultQuoteAnalyzer(parseContext.mapperService().searchQuoteAnalyzer());
|
||||
|
||||
if (qpSettings.queryString() == null) {
|
||||
throw new QueryParsingException(parseContext.index(), "No value specified for term query");
|
||||
|
|
|
@ -34,7 +34,7 @@ import static com.google.common.collect.Lists.newArrayList;
|
|||
* will use the {@link #defaultField(String)} set. The second, when one or more fields are added
|
||||
* (using {@link #field(String)}), will run the parsed query against the provided fields, and combine
|
||||
* them either using DisMax or a plain boolean query (see {@link #useDisMax(boolean)}).
|
||||
*
|
||||
* <p/>
|
||||
* (shay.baon)
|
||||
*/
|
||||
public class QueryStringQueryBuilder extends BaseQueryBuilder {
|
||||
|
@ -51,6 +51,9 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
|
|||
private Operator defaultOperator;
|
||||
|
||||
private String analyzer;
|
||||
private String quoteAnalyzer;
|
||||
|
||||
private String quoteFieldSuffix;
|
||||
|
||||
private Boolean autoGeneratePhraseQueries;
|
||||
|
||||
|
@ -163,6 +166,16 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The optional analyzer used to analyze the query string for phrase searches. Note, if a field has search (quote) analyzer
|
||||
* defined for it, then it will be used automatically. Defaults to the smart search analyzer.
|
||||
*/
|
||||
public QueryStringQueryBuilder quoteAnalyzer(String analyzer) {
|
||||
this.quoteAnalyzer = analyzer;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set to true if phrase queries will be automatically generated
|
||||
* when the analyzer returns more than one term from whitespace
|
||||
|
@ -258,6 +271,14 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional field name suffix to automatically try and add to the field searched when using quoted text.
|
||||
*/
|
||||
public QueryStringQueryBuilder quoteFieldSuffix(String quoteFieldSuffix) {
|
||||
this.quoteFieldSuffix = quoteFieldSuffix;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(QueryStringQueryParser.NAME);
|
||||
|
@ -291,6 +312,9 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
|
|||
if (analyzer != null) {
|
||||
builder.field("analyzer", analyzer);
|
||||
}
|
||||
if (quoteAnalyzer != null) {
|
||||
builder.field("quote_analyzer", quoteAnalyzer);
|
||||
}
|
||||
if (autoGeneratePhraseQueries != null) {
|
||||
builder.field("auto_generate_phrase_queries", autoGeneratePhraseQueries);
|
||||
}
|
||||
|
@ -324,6 +348,9 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
|
|||
if (minimumShouldMatch != null) {
|
||||
builder.field("minimum_should_match", minimumShouldMatch);
|
||||
}
|
||||
if (quoteFieldSuffix != null) {
|
||||
builder.field("quote_field_suffix", quoteFieldSuffix);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,6 +142,12 @@ public class QueryStringQueryParser implements QueryParser {
|
|||
throw new QueryParsingException(parseContext.index(), "[query_string] analyzer [" + parser.text() + "] not found");
|
||||
}
|
||||
qpSettings.forcedAnalyzer(analyzer);
|
||||
} else if ("quote_analyzer".equals(currentFieldName) || "quoteAnalyzer".equals(currentFieldName)) {
|
||||
NamedAnalyzer analyzer = parseContext.analysisService().analyzer(parser.text());
|
||||
if (analyzer == null) {
|
||||
throw new QueryParsingException(parseContext.index(), "[query_string] quote_analyzer [" + parser.text() + "] not found");
|
||||
}
|
||||
qpSettings.forcedQuoteAnalyzer(analyzer);
|
||||
} else if ("allow_leading_wildcard".equals(currentFieldName) || "allowLeadingWildcard".equals(currentFieldName)) {
|
||||
qpSettings.allowLeadingWildcard(parser.booleanValue());
|
||||
} else if ("auto_generate_phrase_queries".equals(currentFieldName) || "autoGeneratePhraseQueries".equals(currentFieldName)) {
|
||||
|
@ -170,6 +176,8 @@ public class QueryStringQueryParser implements QueryParser {
|
|||
qpSettings.rewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull()));
|
||||
} else if ("minimum_should_match".equals(currentFieldName) || "minimumShouldMatch".equals(currentFieldName)) {
|
||||
qpSettings.minimumShouldMatch(parser.textOrNull());
|
||||
} else if ("quote_field_suffix".equals(currentFieldName) || "quoteFieldSuffix".equals(currentFieldName)) {
|
||||
qpSettings.quoteFieldSuffix(parser.textOrNull());
|
||||
} else {
|
||||
throw new QueryParsingException(parseContext.index(), "[query_string] query does not support [" + currentFieldName + "]");
|
||||
}
|
||||
|
@ -179,6 +187,7 @@ public class QueryStringQueryParser implements QueryParser {
|
|||
throw new QueryParsingException(parseContext.index(), "query_string must be provided with a [query]");
|
||||
}
|
||||
qpSettings.defaultAnalyzer(parseContext.mapperService().searchAnalyzer());
|
||||
qpSettings.defaultQuoteAnalyzer(parseContext.mapperService().searchQuoteAnalyzer());
|
||||
|
||||
if (qpSettings.escape()) {
|
||||
qpSettings.queryString(org.apache.lucene.queryParser.QueryParser.escape(qpSettings.queryString()));
|
||||
|
|
Loading…
Reference in New Issue