package org.apache.blur.analysis.type.spatial; /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF 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. */ import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.blur.analysis.type.CustomFieldTypeDefinition; import org.apache.blur.analysis.type.MultiValuedNotAllowedException; import org.apache.blur.thrift.generated.Column; import org.apache.lucene.document.Field; import org.apache.lucene.document.StoredField; import org.apache.lucene.search.Query; import org.apache.lucene.spatial.SpatialStrategy; import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree; import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree; import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree; import org.apache.lucene.spatial.query.SpatialArgs; import org.apache.lucene.spatial.query.SpatialOperation; import com.spatial4j.core.context.SpatialContext; import com.spatial4j.core.shape.Shape; public abstract class BaseSpatialFieldTypeDefinition extends CustomFieldTypeDefinition { public static final String QUAD = "Quad("; public static final String END = ")"; public static final String GEO_HASH = "GeoHash("; public static final String GEOHASH_PREFIX_TREE = "GeohashPrefixTree"; public static final String QUAD_PREFIX_TREE = "QuadPrefixTree"; public static final String SPATIAL_PREFIX_TREE = "spatialPrefixTree"; public static final String MAX_LEVELS = "maxLevels"; protected SpatialStrategy _strategy; protected SpatialContext _ctx; protected SpatialPrefixTree _grid; protected ShapeReadWriter<SpatialContext> _shapeReadWriter; protected List<SpatialOperation> _supportedOperations; protected List<Class<? extends Shape>> _supportedIndexedShapes; @Override public Iterable<? extends Field> getFieldsForColumn(String family, Column column) { synchronized (_strategy) { String name = getName(family, column.getName()); if (!_strategy.getFieldName().equals(name)) { throw new RuntimeException("Strategy name and column name do not match."); } List<Field> fields = new ArrayList<Field>(); Shape shape = getShape(column); checkShape(shape); for (Field f : _strategy.createIndexableFields(shape)) { fields.add(f); } fields.add(new StoredField(name, column.getValue())); return fields; } } @Override public Iterable<? extends Field> getFieldsForSubColumn(String family, Column column, String subName) { synchronized (_strategy) { String name = getName(family, column.getName(), subName); if (!_strategy.getFieldName().equals(name)) { throw new RuntimeException("Strategy name and column name do not match."); } List<Field> fields = new ArrayList<Field>(); Shape shape = getShape(column); checkShape(shape); for (Field f : _strategy.createIndexableFields(shape)) { fields.add(f); } return fields; } } @Override public Query getCustomQuery(String text) { SpatialArgs args = SpatialArgsParser.parse(text, _shapeReadWriter); checkSpatialArgs(args); synchronized (_strategy) { return _strategy.makeQuery(args); } } protected void checkShape(Shape shape) { for (Class<? extends Shape> shapeType : _supportedIndexedShapes) { if (shapeType.isInstance(shape)) { return; } } throw new IllegalArgumentException(_strategy.getClass().getName() + " only supports [" + _supportedIndexedShapes + "] operation."); } protected void checkSpatialArgs(SpatialArgs args) { SpatialOperation operation = args.getOperation(); for (SpatialOperation so : _supportedOperations) { if (operation == so) { return; } } throw new IllegalArgumentException(_strategy.getClass().getName() + " only supports [" + _supportedOperations + "] operation."); } protected Shape getShape(Column column) { return _shapeReadWriter.readShape(column.getValue()); } protected SpatialPrefixTree getSpatialPrefixTree(String field, Map<String, String> properties) { String spatialPrefixTreeStr = properties.get(SPATIAL_PREFIX_TREE); if (spatialPrefixTreeStr == null) { throw new IllegalArgumentException("Property [" + SPATIAL_PREFIX_TREE + "] is missing from type def for field [" + field + "]"); } else if (spatialPrefixTreeStr.equals(GEOHASH_PREFIX_TREE)) { int maxLevels = getMaxLevels(properties); return new GeohashPrefixTree(_ctx, maxLevels); } else if (spatialPrefixTreeStr.equals(QUAD_PREFIX_TREE)) { int maxLevels = getMaxLevels(properties); return new QuadPrefixTree(_ctx, maxLevels); } else { throw new RuntimeException("Unknown spatialPrefixTreeStr [" + spatialPrefixTreeStr + "]"); } } protected int getMaxLevels(Map<String, String> properties) { String maxLevelsStr = properties.get(MAX_LEVELS); int maxLevels = 11; if (maxLevelsStr != null) { maxLevels = Integer.parseInt(maxLevelsStr.trim()); } return maxLevels; } public List<SpatialOperation> getSupportedOperations() { return _supportedOperations; } public void setSupportedOperations(List<SpatialOperation> supportedOperations) { _supportedOperations = supportedOperations; } public void addSupportedOperations(SpatialOperation so) { if (_supportedOperations == null) { _supportedOperations = new ArrayList<SpatialOperation>(); } _supportedOperations.add(so); } public List<Class<? extends Shape>> getSupportedIndexedShapes() { return _supportedIndexedShapes; } public void setSupportedIndexedShapes(List<Class<? extends Shape>> supportedIndexedShapes) { _supportedIndexedShapes = supportedIndexedShapes; } public void addSupportedIndexedShapes(Class<? extends Shape> c) { if (_supportedIndexedShapes == null) { _supportedIndexedShapes = new ArrayList<Class<? extends Shape>>(); } _supportedIndexedShapes.add(c); } @Override public void setMultiValueField(boolean multiValueField) { if (!multiValueField) { super.setMultiValueField(multiValueField); } else { throw new MultiValuedNotAllowedException("Field type [" + getName() + "] can not multi valued."); } } }