/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.
*/
package org.elasticsearch.index.search.geo;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RandomAccessWeight;
import org.apache.lucene.search.Weight;
import org.apache.lucene.util.Bits;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
import org.elasticsearch.index.fielddata.MultiGeoPointValues;
import java.io.IOException;
/**
*
*/
public class InMemoryGeoBoundingBoxQuery extends Query {
private final GeoPoint topLeft;
private final GeoPoint bottomRight;
private final IndexGeoPointFieldData indexFieldData;
public InMemoryGeoBoundingBoxQuery(GeoPoint topLeft, GeoPoint bottomRight, IndexGeoPointFieldData indexFieldData) {
this.topLeft = topLeft;
this.bottomRight = bottomRight;
this.indexFieldData = indexFieldData;
}
public GeoPoint topLeft() {
return topLeft;
}
public GeoPoint bottomRight() {
return bottomRight;
}
public String fieldName() {
return indexFieldData.getFieldNames().indexName();
}
@Override
public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
return new RandomAccessWeight(this) {
@Override
protected Bits getMatchingDocs(LeafReaderContext context) throws IOException {
final int maxDoc = context.reader().maxDoc();
final MultiGeoPointValues values = indexFieldData.load(context).getGeoPointValues();
// checks to see if bounding box crosses 180 degrees
if (topLeft.lon() > bottomRight.lon()) {
return new Meridian180GeoBoundingBoxBits(maxDoc, values, topLeft, bottomRight);
} else {
return new GeoBoundingBoxBits(maxDoc, values, topLeft, bottomRight);
}
}
};
}
@Override
public String toString(String field) {
return "GeoBoundingBoxFilter(" + indexFieldData.getFieldNames().indexName() + ", " + topLeft + ", " + bottomRight + ")";
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) == false) {
return false;
}
InMemoryGeoBoundingBoxQuery other = (InMemoryGeoBoundingBoxQuery) obj;
return fieldName().equalsIgnoreCase(other.fieldName())
&& topLeft.equals(other.topLeft)
&& bottomRight.equals(other.bottomRight);
}
@Override
public int hashCode() {
int h = super.hashCode();
h = 31 * h + fieldName().hashCode();
h = 31 * h + topLeft.hashCode();
h = 31 * h + bottomRight.hashCode();
return h;
}
private static class Meridian180GeoBoundingBoxBits implements Bits {
private final int maxDoc;
private final MultiGeoPointValues values;
private final GeoPoint topLeft;
private final GeoPoint bottomRight;
public Meridian180GeoBoundingBoxBits(int maxDoc, MultiGeoPointValues values, GeoPoint topLeft, GeoPoint bottomRight) {
this.maxDoc = maxDoc;
this.values = values;
this.topLeft = topLeft;
this.bottomRight = bottomRight;
}
@Override
public boolean get(int doc) {
values.setDocument(doc);
final int length = values.count();
for (int i = 0; i < length; i++) {
GeoPoint point = values.valueAt(i);
if (((topLeft.lon() <= point.lon() || bottomRight.lon() >= point.lon())) &&
(topLeft.lat() >= point.lat() && bottomRight.lat() <= point.lat())) {
return true;
}
}
return false;
}
@Override
public int length() {
return maxDoc;
}
}
private static class GeoBoundingBoxBits implements Bits {
private final int maxDoc;
private final MultiGeoPointValues values;
private final GeoPoint topLeft;
private final GeoPoint bottomRight;
public GeoBoundingBoxBits(int maxDoc, MultiGeoPointValues values, GeoPoint topLeft, GeoPoint bottomRight) {
this.maxDoc = maxDoc;
this.values = values;
this.topLeft = topLeft;
this.bottomRight = bottomRight;
}
@Override
public boolean get(int doc) {
values.setDocument(doc);
final int length = values.count();
for (int i = 0; i < length; i++) {
GeoPoint point = values.valueAt(i);
if (topLeft.lon() <= point.lon() && bottomRight.lon() >= point.lon()
&& topLeft.lat() >= point.lat() && bottomRight.lat() <= point.lat()) {
return true;
}
}
return false;
}
@Override
public int length() {
return maxDoc;
}
}
}