/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2005, Institut de Recherche pour le Développement * (C) 2007-2009, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.lucene.filter; import java.util.ArrayList; import java.util.List; import java.util.Objects; import org.apache.lucene.search.Filter; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; import org.geotoolkit.index.LogicalFilterType; import org.geotoolkit.index.tree.Tree; import org.opengis.util.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.operation.TransformException; /** * * @author guilhem * @author Johann Sorel (Geomatys) * @module */ public class SpatialQuery implements org.geotoolkit.index.SpatialQuery { /** * The spatial filter added to the lucene query. */ private final Filter spatialFilter ; /** * The lucene query */ private final StringBuilder query; /** * Logical operator to apply between the spatial filter and the query * default operator is AND. */ private final LogicalFilterType logicalOperator; /** * A list of sub-queries with have to be executed separely. */ private final List<SpatialQuery> subQueries = new ArrayList<>(); /** * An lucene Sort object allowing to sort the results */ private Sort sort; /** * Build a new Simple Text Query. * * @param query A well-formed Lucene query. */ public SpatialQuery(final String query) { this(query,null,LogicalFilterType.AND,null); } /** * Build a new Query combinating a lucene query and a spatial filter. * * @param spatialFilter spatial filter * * @throws org.opengis.referencing.NoSuchAuthorityCodeException * @throws org.opengis.util.FactoryException * @throws org.opengis.referencing.operation.TransformException */ public SpatialQuery(final LuceneOGCFilter spatialFilter) throws NoSuchAuthorityCodeException, FactoryException, TransformException { this("",spatialFilter,LogicalFilterType.AND); } /** * Build a new Query combinating a lucene query and a lucene filter. * * @param query A well-formed Lucene query. * @param filter A lucene filter (spatial, serialChain, ...) * @param logicalOperator The logical operator to apply between the query and the spatialFilter. */ public SpatialQuery(final String query, final Filter filter, final LogicalFilterType logicalOperator) { this(query,filter,logicalOperator,null); } private SpatialQuery(final String query, final Filter filter, final LogicalFilterType logicalOperator, final List<SpatialQuery> sub){ this.query = new StringBuilder(query); this.spatialFilter = filter; this.logicalOperator = logicalOperator; if(sub != null){ this.subQueries.addAll(sub); } } /** * Return the spatial filter (it can be a SerialChainFilter) to add to the lucene query. */ @Override public Filter getSpatialFilter() { return spatialFilter; } /** * Return the lucene query associated with the filter. */ @Override public String getQuery() { if (query == null || query.toString().equals("") || query.toString().equals(" ")) { return "metafile:doc"; } return query.toString(); } /** * Return the logical operator to apply between the query and the filter. */ public LogicalFilterType getLogicalOperator() { return logicalOperator; } /** * Return the sort Object joinded to this Query. */ public Sort getSort() { return sort; } /** * Add a sort Object to the query * * @param sort */ public void setSort(final Sort sort) { this.sort = sort; for (SpatialQuery sub: getSubQueries()) { sub.setSort(sort); } } @Override public void setSort(String fieldName, boolean desc, Character fieldType) { final SortField sf; if (fieldType != null) { switch (fieldType) { case 'd': sf = new SortField(fieldName, SortField.Type.DOUBLE, desc);break; case 'i': sf = new SortField(fieldName, SortField.Type.INT, desc);break; case 'f': sf = new SortField(fieldName, SortField.Type.FLOAT, desc);break; case 'l': sf = new SortField(fieldName, SortField.Type.LONG, desc);break; default : sf = new SortField(fieldName, SortField.Type.STRING, desc);break; } } else { sf = new SortField(fieldName, SortField.Type.STRING, desc); } final Sort sortFilter = new Sort(sf); setSort(sortFilter); } /** * Return the subQueries joined to this query. */ public List<SpatialQuery> getSubQueries() { return subQueries; } /** * Set the sub-queries list. * * @param subQueries a list of spatial queries. */ public void setSubQueries(final List<SpatialQuery> subQueries) { this.subQueries.clear(); this.subQueries.addAll(subQueries); } /** * Add a new spatial query to the list of sub-queries * * @param sq a spatial query. */ public void addSubQuery(final SpatialQuery sq) { subQueries.add(sq); } /** * Set the lucene query associated with the filter. */ public void setQuery(final String query) { this.query.delete(0, this.query.length()-1); this.query.append(query); } /** * Append a piece of lucene query to the main query. * * @param s a piece of lucene query. */ public void appendToQuery(final String s) { query.append(s); } public void applyRtreeOnFilter(final Tree rTree, final boolean envelopeOnly) { if (spatialFilter instanceof org.geotoolkit.lucene.filter.Filter) { ((org.geotoolkit.lucene.filter.Filter)spatialFilter).applyRtreeOnFilter(rTree, envelopeOnly); } } /** * Return a String representation of the object. */ @Override public String toString() { StringBuilder s = new StringBuilder("[SpatialQuery]:").append('\n'); if (spatialFilter == null && !query.toString().equals("") && logicalOperator == LogicalFilterType.NOT) { s.append("query: NOT <").append(query).append(">").append('\n'); } else if (!query.toString().equals("")) { s.append('\t').append("query: |").append(query.toString()).append('|').append('\n'); } if (spatialFilter != null && !query.toString().equals("")) { s.append(SerialChainFilter.valueOf(logicalOperator)).append('\n'); } if (spatialFilter != null) { s.append('\t').append(spatialFilter).append('\n'); } if (subQueries != null && subQueries.size() > 0) { s.append("subqueries:").append('\n'); int i = 0; for (SpatialQuery sq: subQueries) { s.append("sub ").append(i).append(':').append(sq); i++; } } if (sort != null) { s.append("Sort: ").append(sort).append('\n'); } return s.toString(); } /** * Verify if this entry is identical to the specified object. */ @Override public boolean equals(final Object object) { if (object == this) { return true; } if (object instanceof SpatialQuery) { final SpatialQuery that = (SpatialQuery) object; return (this.logicalOperator == that.logicalOperator) && Objects.equals(this.getQuery(), that.getQuery()) && Objects.equals(this.sort, that.sort) && Objects.equals(this.spatialFilter, that.spatialFilter) && Objects.equals(this.subQueries, that.subQueries); } return false; } @Override public int hashCode() { int hash = 5; hash = 97 * hash + (this.spatialFilter != null ? this.spatialFilter.hashCode() : 0); hash = 97 * hash + (this.query != null ? getQuery().hashCode() : 0); hash = 97 * hash + (this.logicalOperator != null ? logicalOperator.hashCode() : 0); hash = 97 * hash + (this.subQueries != null ? this.subQueries.hashCode() : 0); hash = 97 * hash + (this.sort != null ? this.sort.hashCode() : 0); return hash; } }