/* * Copyright 2004-2009 the original 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.compass.core.impl; import java.io.Reader; import java.io.Serializable; import org.compass.core.CompassException; import org.compass.core.CompassQuery; import org.compass.core.CompassQuery.CompassSpanQuery; import org.compass.core.CompassQueryBuilder; import org.compass.core.Resource; import org.compass.core.engine.SearchEngineQuery; import org.compass.core.engine.SearchEngineQuery.SearchEngineSpanQuery; import org.compass.core.engine.SearchEngineQueryBuilder; import org.compass.core.engine.SearchEngineQueryBuilder.SearchEngineBooleanQueryBuilder; import org.compass.core.engine.SearchEngineQueryBuilder.SearchEngineMultiPhraseQueryBuilder; import org.compass.core.engine.SearchEngineQueryBuilder.SearchEngineMultiPropertyQueryStringBuilder; import org.compass.core.engine.SearchEngineQueryBuilder.SearchEngineQuerySpanNearBuilder; import org.compass.core.engine.SearchEngineQueryBuilder.SearchEngineQuerySpanOrBuilder; import org.compass.core.engine.SearchEngineQueryBuilder.SearchEngineQueryStringBuilder; import org.compass.core.mapping.ResourcePropertyLookup; import org.compass.core.spi.InternalCompass; import org.compass.core.spi.InternalCompassQuery; import org.compass.core.spi.InternalCompassSession; import org.compass.core.spi.InternalCompassSpanQuery; /** * @author kimchy */ public class DefaultCompassQueryBuilder implements CompassQueryBuilder { public class DefaultCompassBooleanQueryBuilder implements CompassBooleanQueryBuilder { private SearchEngineBooleanQueryBuilder queryBuilder; public DefaultCompassBooleanQueryBuilder(SearchEngineBooleanQueryBuilder queryBuilder) { this.queryBuilder = queryBuilder; } public CompassBooleanQueryBuilder addMust(CompassQuery query) { queryBuilder.addMust(((DefaultCompassQuery) query).getSearchEngineQuery()); return this; } public CompassBooleanQueryBuilder addMustNot(CompassQuery query) { queryBuilder.addMustNot(((DefaultCompassQuery) query).getSearchEngineQuery()); return this; } public CompassBooleanQueryBuilder addShould(CompassQuery query) { queryBuilder.addShould(((DefaultCompassQuery) query).getSearchEngineQuery()); return this; } public CompassBooleanQueryBuilder setMinimumNumberShouldMatch(int min) { queryBuilder.setMinimumNumberShouldMatch(min); return this; } public CompassQuery toQuery() { return buildCompassQuery(queryBuilder.toQuery()); } } public class DefaultCompassMultiPhraseQueryBuilder implements CompassMultiPhraseQueryBuilder { private SearchEngineMultiPhraseQueryBuilder queryBuilder; private ResourcePropertyLookup lookup; public DefaultCompassMultiPhraseQueryBuilder(SearchEngineMultiPhraseQueryBuilder queryBuilder, ResourcePropertyLookup lookup) { this.queryBuilder = queryBuilder; this.lookup = lookup; } public CompassMultiPhraseQueryBuilder setSlop(int slop) { queryBuilder.setSlop(slop); return this; } public CompassMultiPhraseQueryBuilder add(Object value) { queryBuilder.add(lookup.getValue(value)); return this; } public CompassMultiPhraseQueryBuilder add(Object value, int position) { queryBuilder.add(lookup.getValue(value), position); return this; } public CompassMultiPhraseQueryBuilder add(Object[] values) { String[] strValues = new String[values.length]; for (int i = 0; i < values.length; i++) { strValues[i] = lookup.getValue(values[i]); } queryBuilder.add(strValues); return this; } public CompassMultiPhraseQueryBuilder add(Object[] values, int position) { String[] strValues = new String[values.length]; for (int i = 0; i < values.length; i++) { strValues[i] = lookup.getValue(values[i]); } queryBuilder.add(strValues, position); return this; } public CompassQuery toQuery() { return buildCompassQuery(queryBuilder.toQuery()); } } public class DefaultCompassQueryStringBuilder implements CompassQueryStringBuilder { private SearchEngineQueryStringBuilder queryBuilder; public DefaultCompassQueryStringBuilder(SearchEngineQueryStringBuilder queryBuilder) { this.queryBuilder = queryBuilder; } public CompassQueryStringBuilder setAnalyzer(String analyzer) throws CompassException { queryBuilder.setAnalyzer(analyzer); return this; } public CompassQueryStringBuilder setAnalyzerByAlias(String alias) throws CompassException { queryBuilder.setAnalyzerByAlias(alias); return this; } public CompassQueryStringBuilder setQueryParser(String queryParser) throws CompassException { queryBuilder.setQueryParser(queryParser); return this; } public CompassQueryStringBuilder useSpellCheck() throws CompassException { queryBuilder.useSpellCheck(); return this; } public CompassQueryStringBuilder setDefaultSearchProperty(String defaultSearchProperty) { queryBuilder.setDefaultSearchProperty(defaultSearchProperty); return this; } public CompassQueryStringBuilder useAndDefaultOperator() { queryBuilder.useAndDefaultOperator(); return this; } public CompassQueryStringBuilder useOrDefaultOperator() { queryBuilder.useOrDefaultOperator(); return this; } public CompassQueryStringBuilder forceAnalyzer() { queryBuilder.forceAnalyzer(); return this; } public CompassQuery toQuery() { return buildCompassQuery(queryBuilder.toQuery()); } } public class DefaultCompassMultiPropertyQueryStringBuilder implements CompassMultiPropertyQueryStringBuilder { private SearchEngineMultiPropertyQueryStringBuilder queryBuilder; public DefaultCompassMultiPropertyQueryStringBuilder(SearchEngineMultiPropertyQueryStringBuilder queryBuilder) { this.queryBuilder = queryBuilder; } public CompassMultiPropertyQueryStringBuilder setAnalyzer(String analyzer) throws CompassException { queryBuilder.setAnalyzer(analyzer); return this; } public CompassMultiPropertyQueryStringBuilder setAnalyzerByAlias(String alias) throws CompassException { queryBuilder.setAnalyzerByAlias(alias); return this; } public CompassMultiPropertyQueryStringBuilder setQueryParser(String queryParser) throws CompassException { queryBuilder.setQueryParser(queryParser); return this; } public CompassMultiPropertyQueryStringBuilder useSpellCheck() { queryBuilder.useSpellCheck(); return this; } public CompassMultiPropertyQueryStringBuilder add(String name) { queryBuilder.add(compass.getMapping().getResourcePropertyLookup(name).getPath()); return this; } public CompassMultiPropertyQueryStringBuilder useAndDefaultOperator() { queryBuilder.useAndDefaultOperator(); return this; } public CompassMultiPropertyQueryStringBuilder useOrDefaultOperator() { queryBuilder.useOrDefaultOperator(); return this; } public CompassMultiPropertyQueryStringBuilder forceAnalyzer() { queryBuilder.forceAnalyzer(); return this; } public CompassQuery toQuery() { return buildCompassQuery(queryBuilder.toQuery()); } } public class DefaultCompassQuerySpanNearBuilder implements CompassQuerySpanNearBuilder { private SearchEngineQuerySpanNearBuilder queryBuilder; private ResourcePropertyLookup lookup; public DefaultCompassQuerySpanNearBuilder(SearchEngineQuerySpanNearBuilder queryBuilder, ResourcePropertyLookup lookup) { this.queryBuilder = queryBuilder; this.lookup = lookup; } public CompassQuerySpanNearBuilder setSlop(int slop) { queryBuilder.setSlop(slop); return this; } public CompassQuerySpanNearBuilder setInOrder(boolean inOrder) { queryBuilder.setInOrder(inOrder); return this; } public CompassQuerySpanNearBuilder add(Object value) { queryBuilder.add(lookup.getValue(value)); return this; } public CompassQuerySpanNearBuilder add(CompassSpanQuery query) { queryBuilder.add(((DefaultCompassQuery.DefaultCompassSpanQuey) query).getSearchEngineSpanQuery()); return this; } public CompassSpanQuery toQuery() { SearchEngineSpanQuery query = queryBuilder.toQuery(); return buildCompassQuery(query); } } public class DefaultCompassQuerySpanOrBuilder implements CompassQuerySpanOrBuilder { private SearchEngineQuerySpanOrBuilder queryBuilder; public DefaultCompassQuerySpanOrBuilder(SearchEngineQuerySpanOrBuilder queryBuilder) { this.queryBuilder = queryBuilder; } public CompassQuerySpanOrBuilder add(CompassSpanQuery query) { queryBuilder.add(((DefaultCompassQuery.DefaultCompassSpanQuey) query).getSearchEngineSpanQuery()); return this; } public CompassSpanQuery toQuery() { SearchEngineSpanQuery query = queryBuilder.toQuery(); return buildCompassQuery(query); } } public class DefaultCompassMoreLikeThisQuery implements CompassMoreLikeThisQuery { private SearchEngineQueryBuilder.SearchEngineMoreLikeThisQueryBuilder queryBuilder; private InternalCompassSession session; public DefaultCompassMoreLikeThisQuery(SearchEngineQueryBuilder.SearchEngineMoreLikeThisQueryBuilder queryBuilder, InternalCompassSession session) { this.queryBuilder = queryBuilder; this.session = session; } public CompassMoreLikeThisQuery setSubIndexes(String[] subIndexes) { queryBuilder.setSubIndexes(subIndexes); return this; } public CompassMoreLikeThisQuery setAliases(String[] aliases) { queryBuilder.setAliases(aliases); return this; } public CompassMoreLikeThisQuery setProperties(String[] properties) { if (properties == null) { queryBuilder.setProperties(properties); } else { String[] updatedProperties = new String[properties.length]; for (int i = 0; i < properties.length; i++) { ResourcePropertyLookup lookup = session.getMapping().getResourcePropertyLookup(properties[i]); updatedProperties[i] = lookup.getPath(); } queryBuilder.setProperties(updatedProperties); } return this; } public CompassMoreLikeThisQuery addProperty(String property) { ResourcePropertyLookup lookup = session.getMapping().getResourcePropertyLookup(property); queryBuilder.addProperty(lookup.getPath()); return this; } public CompassMoreLikeThisQuery setAnalyzer(String analyzer) { queryBuilder.setAnalyzer(analyzer); return this; } public CompassMoreLikeThisQuery setBoost(boolean boost) { queryBuilder.setBoost(boost); return this; } public CompassMoreLikeThisQuery setMaxNumTokensParsed(int maxNumTokensParsed) { queryBuilder.setMaxNumTokensParsed(maxNumTokensParsed); return this; } public CompassMoreLikeThisQuery setMaxQueryTerms(int maxQueryTerms) { queryBuilder.setMaxQueryTerms(maxQueryTerms); return this; } public CompassMoreLikeThisQuery setMaxWordLen(int maxWordLen) { queryBuilder.setMaxWordLen(maxWordLen); return this; } public CompassMoreLikeThisQuery setMinWordLen(int minWordLen) { queryBuilder.setMinWordLen(minWordLen); return this; } public CompassMoreLikeThisQuery setMinResourceFreq(int minDocFreq) { queryBuilder.setMinResourceFreq(minDocFreq); return this; } public CompassMoreLikeThisQuery setMinTermFreq(int minTermFreq) { queryBuilder.setMinTermFreq(minTermFreq); return this; } public CompassMoreLikeThisQuery setStopWords(String[] stopWords) { queryBuilder.setStopWords(stopWords); return this; } public CompassQuery toQuery() { return buildCompassQuery(queryBuilder.toQuery()); } } private final SearchEngineQueryBuilder queryBuilder; private final InternalCompass compass; private final InternalCompassSession session; private boolean convertOnlyWithDotPath = false; private boolean addAliasQueryIfNeeded = true; public DefaultCompassQueryBuilder(SearchEngineQueryBuilder queryBuilder, InternalCompass compass) { this(queryBuilder, compass, null); } public DefaultCompassQueryBuilder(SearchEngineQueryBuilder queryBuilder, InternalCompass compass, InternalCompassSession session) { this.queryBuilder = queryBuilder; this.compass = compass; this.session = session; } public CompassQueryBuilder convertOnlyWithDotPath(boolean convertOnlyWithDotPath) { this.convertOnlyWithDotPath = convertOnlyWithDotPath; return this; } public CompassQueryBuilder addAliasQueryIfNeeded(boolean addAliasQueryIfNeeded) { this.addAliasQueryIfNeeded = addAliasQueryIfNeeded; return this; } public CompassBooleanQueryBuilder bool() { return new DefaultCompassBooleanQueryBuilder(queryBuilder.bool()); } public CompassBooleanQueryBuilder bool(boolean disableCoord) { return new DefaultCompassBooleanQueryBuilder(queryBuilder.bool(disableCoord)); } public CompassMultiPhraseQueryBuilder multiPhrase(String name) { ResourcePropertyLookup lookup = getLookup(name); return new DefaultCompassMultiPhraseQueryBuilder(queryBuilder.multiPhrase(lookup.getPath()), lookup); } public CompassQueryStringBuilder queryString(String queryString) { return new DefaultCompassQueryStringBuilder(queryBuilder.queryString(queryString)); } public CompassMultiPropertyQueryStringBuilder multiPropertyQueryString(String queryString) { return new DefaultCompassMultiPropertyQueryStringBuilder(queryBuilder.multiPropertyQueryString(queryString)); } public CompassQuery alias(String aliasValue) { if (!compass.getMapping().hasRootMappingByAlias(aliasValue)) { throw new CompassException("Alias [" + aliasValue + "] not found in Compass mappings definitions"); } String aliasProperty = compass.getSearchEngineFactory().getAliasProperty(); SearchEngineQuery query = queryBuilder.term(aliasProperty, aliasValue); return buildCompassQuery(query); } public CompassQuery polyAlias(String aliasValue) { return bool().addShould(term(compass.getSearchEngineFactory().getAliasProperty(), aliasValue)) .addShould(term(compass.getSearchEngineFactory().getExtendedAliasProperty(), aliasValue)) .setMinimumNumberShouldMatch(1) .toQuery(); } public CompassQuery term(String name, Object value) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.term(lookup.getPath(), lookup.getValue(value)); InternalCompassQuery compassQuery = new DefaultCompassQuery(wrapWithAliasQueryIfNeeded(lookup, query), compass); attachIfPossible(compassQuery); return compassQuery; } public CompassQuery matchAll() { SearchEngineQuery query = queryBuilder.matchAll(); return buildCompassQuery(query); } public CompassQuery between(String name, Object low, Object high, boolean inclusive, boolean constantScore) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.between(lookup.getPath(), lookup.getValue(low), lookup.getValue(high), inclusive, constantScore); return buildCompassQuery(query, lookup); } public CompassQuery between(String name, Object low, Object high, boolean inclusive) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.between(lookup.getPath(), lookup.getValue(low), lookup.getValue(high), inclusive); return buildCompassQuery(query, lookup); } public CompassQuery lt(String name, Object value) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.lt(lookup.getPath(), lookup.getValue(value)); return buildCompassQuery(query, lookup); } public CompassQuery le(String name, Object value) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.le(lookup.getPath(), lookup.getValue(value)); return buildCompassQuery(query, lookup); } public CompassQuery gt(String name, Object value) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.gt(lookup.getPath(), lookup.getValue(value)); return buildCompassQuery(query, lookup); } public CompassQuery ge(String name, Object value) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.ge(lookup.getPath(), lookup.getValue(value)); return buildCompassQuery(query, lookup); } public CompassQuery prefix(String name, String prefix) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.prefix(lookup.getPath(), prefix); return buildCompassQuery(query, lookup); } public CompassQuery wildcard(String name, String wildcard) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.wildcard(lookup.getPath(), wildcard); return buildCompassQuery(query, lookup); } public CompassQuery fuzzy(String name, String value, float minimumSimilarity) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.fuzzy(lookup.getPath(), value, minimumSimilarity); return buildCompassQuery(query, lookup); } public CompassQuery fuzzy(String name, String value, float minimumSimilarity, int prefixLength) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.fuzzy(lookup.getPath(), value, minimumSimilarity, prefixLength); return buildCompassQuery(query, lookup); } public CompassQuery fuzzy(String name, String value) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineQuery query = queryBuilder.fuzzy(lookup.getPath(), value); return buildCompassQuery(query, lookup); } public CompassSpanQuery spanEq(String name, Object value) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineSpanQuery query = queryBuilder.spanEq(lookup.getPath(), lookup.getValue(value)); return buildCompassQuery(query); } public CompassSpanQuery spanFirst(String name, Object value, int end) { ResourcePropertyLookup lookup = getLookup(name); SearchEngineSpanQuery query = queryBuilder.spanFirst(lookup.getPath(), lookup.getValue(value), end); return buildCompassQuery(query); } public CompassSpanQuery spanFirst(CompassSpanQuery spanQuery, int end) { SearchEngineSpanQuery query = queryBuilder.spanFirst(((DefaultCompassQuery.DefaultCompassSpanQuey) spanQuery).getSearchEngineSpanQuery(), end); return buildCompassQuery(query); } public CompassQuerySpanNearBuilder spanNear(String name) { ResourcePropertyLookup lookup = getLookup(name); return new DefaultCompassQuerySpanNearBuilder(queryBuilder.spanNear(lookup.getPath()), lookup); } public CompassSpanQuery spanNot(CompassSpanQuery include, CompassSpanQuery exclude) { SearchEngineSpanQuery query = queryBuilder.spanNot(((DefaultCompassQuery.DefaultCompassSpanQuey) include) .getSearchEngineSpanQuery(), ((DefaultCompassQuery.DefaultCompassSpanQuey) exclude) .getSearchEngineSpanQuery()); return buildCompassQuery(query); } public CompassQuerySpanOrBuilder spanOr() { return new DefaultCompassQuerySpanOrBuilder(queryBuilder.spanOr()); } public CompassMoreLikeThisQuery moreLikeThis(String alias, Serializable id) { if (session == null) { throw new CompassException("moreLikeThis query can only be used when constructed using a CompassSession"); } Resource idResource = session.getMarshallingStrategy().marshallIds(alias, id); SearchEngineQueryBuilder.SearchEngineMoreLikeThisQueryBuilder mltQueryBuilder = queryBuilder.moreLikeThis(session.getSearchEngine(), idResource); return new DefaultCompassMoreLikeThisQuery(mltQueryBuilder, session); } public CompassMoreLikeThisQuery moreLikeThis(Reader reader) { if (session == null) { throw new CompassException("moreLikeThis query can only be used when constructed using a CompassSession"); } SearchEngineQueryBuilder.SearchEngineMoreLikeThisQueryBuilder mltQueryBuilder = queryBuilder.moreLikeThis(session.getSearchEngine(), reader); return new DefaultCompassMoreLikeThisQuery(mltQueryBuilder, session); } private InternalCompassSpanQuery buildCompassQuery(SearchEngineSpanQuery query) { InternalCompassSpanQuery compassSpanQuery = new DefaultCompassQuery.DefaultCompassSpanQuey(query, compass); attachIfPossible(compassSpanQuery); return compassSpanQuery; } private InternalCompassQuery buildCompassQuery(SearchEngineQuery query, ResourcePropertyLookup lookup) { return buildCompassQuery(wrapWithAliasQueryIfNeeded(lookup, query)); } private InternalCompassQuery buildCompassQuery(SearchEngineQuery query) { InternalCompassQuery compassQuery = new DefaultCompassQuery(query, compass); attachIfPossible(compassQuery); return compassQuery; } private void attachIfPossible(InternalCompassQuery query) { if (session != null) { query.attach(session); session.addDelegateClose(query); } } private SearchEngineQuery wrapWithAliasQueryIfNeeded(ResourcePropertyLookup lookup, SearchEngineQuery query) { if (!addAliasQueryIfNeeded) { return query; } if (lookup == null) { return query; } String alias = lookup.getDotPathAlias(); if (alias == null) { return query; } return queryBuilder.bool() .addMust(query) .addMust(queryBuilder.bool() .addShould(queryBuilder.term(compass.getSearchEngineFactory().getAliasProperty(), alias)) .addShould(queryBuilder.term(compass.getSearchEngineFactory().getExtendedAliasProperty(), alias)) .setMinimumNumberShouldMatch(1) .toQuery()) .toQuery(); } private ResourcePropertyLookup getLookup(String name) { ResourcePropertyLookup lookup = compass.getMapping().getResourcePropertyLookup(name); lookup.setConvertOnlyWithDotPath(convertOnlyWithDotPath); return lookup; } }