/* * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. Crate licenses * this file to you 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. * * However, if you have executed another commercial license agreement * with Crate these terms will supersede the license and you may use the * software solely pursuant to the terms of the relevant commercial agreement. */ package io.crate.operation.predicate; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import io.crate.metadata.FunctionIdent; import io.crate.metadata.FunctionImplementation; import io.crate.metadata.FunctionInfo; import io.crate.types.DataType; import io.crate.types.DataTypes; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.index.query.MultiMatchQueryBuilder; import javax.annotation.Nullable; import java.util.Arrays; import java.util.Locale; import java.util.Map; import java.util.Set; /** * The match predicate is only used to generate lucene queries from. */ public class MatchPredicate implements FunctionImplementation { public static final Set<DataType> SUPPORTED_TYPES = ImmutableSet.of(DataTypes.STRING, DataTypes.GEO_SHAPE); private static final String DEFAULT_MATCH_TYPE_STRING = MultiMatchQueryBuilder.Type.BEST_FIELDS.toString().toLowerCase(Locale.ENGLISH); private static final Map<DataType, String> DATA_TYPE_TO_DEFAULT_MATCH_TYPE = ImmutableMap.of( DataTypes.STRING, DEFAULT_MATCH_TYPE_STRING, DataTypes.GEO_SHAPE, "intersects" ); private static final Set<String> SUPPORTED_GEO_MATCH_TYPES = ImmutableSet.of("intersects", "disjoint", "within"); public static final String NAME = "match"; public static final FunctionIdent IDENT = new FunctionIdent( NAME, Arrays.asList(DataTypes.OBJECT, DataTypes.STRING, DataTypes.STRING, DataTypes.OBJECT) ); public static final FunctionInfo INFO = new FunctionInfo(IDENT, DataTypes.BOOLEAN); private static String defaultMatchType(DataType dataType) { String matchType = DATA_TYPE_TO_DEFAULT_MATCH_TYPE.get(dataType); if (matchType == null) { throw new IllegalArgumentException("No default matchType found for dataType: " + dataType); } return matchType; } public static String getMatchType(@Nullable String matchType, DataType columnType) { if (matchType == null) { return defaultMatchType(columnType); } if (columnType.equals(DataTypes.STRING)) { try { MultiMatchQueryBuilder.Type.parse(matchType, ParseFieldMatcher.STRICT); return matchType; } catch (ElasticsearchParseException e) { throw new IllegalArgumentException(String.format(Locale.ENGLISH, "invalid MATCH type '%s' for type '%s'", matchType, columnType), e); } } else if (columnType.equals(DataTypes.GEO_SHAPE)) { if (!SUPPORTED_GEO_MATCH_TYPES.contains(matchType)) { throw new IllegalArgumentException(String.format(Locale.ENGLISH, "invalid MATCH type '%s' for type '%s', valid types are: [%s]", matchType, columnType, Joiner.on(",").join(SUPPORTED_GEO_MATCH_TYPES))); } return matchType; } throw new IllegalArgumentException("No match type for dataType: " + columnType); } /** * the match predicate is registered as a regular function * though it is called differently by the parser. We mangle * the arguments and options for the match predicate into * function arguments. * <p> * 1. list of column idents and boost values - object mapping column name to boost value (Double) (values nullable) * 2. query string - string * 3. match_type - string (nullable) * 4. match_type options - object mapping option name to value (Object) (nullable) */ public static void register(PredicateModule module) { module.register(new MatchPredicate()); } private MatchPredicate() { } @Override public FunctionInfo info() { return INFO; } }