A Filter is a generic way to get features that satisfy certain criteria. In general, a Filter object takes a Feature and reports whether the Feature is contained in it (that is, it satisfies the Filter condition) or not.

An individual Filter can report whether a Feature is contained, but this is much more useful when combined with Data Access . To get data in GeoTools, one passes a Query to a FeatureSource. A Filter can be included in the Query to limit the features returned to only those that meet the coniditions of the Filter.

GeoTools does a number of smart things with a Filter passed in, so that all data formats support all Filters. If the format is a database that can transform the Filter into a SQL "where" clause then it will. If it is a spatial database it will turn spatial filters into the equivalent operations. If the format does not support the Filter operation than it will be performed in GeoTools with Java code.

GeoTools will even split up logic filters into their constituent 'supported' and 'unsupported' compenents, passing as much as possible in the native backend datastore, defaulting to java when not possible. The WFS DataStore goes even further, as different WFS implementations support different Filter sets, so it dynamically figures out how much of the filter to have the WFS perform, and how much to do in Java. For example a 'Contains' filter will be passed as an XML filter to GeoServer, but not to MapServer - but using the Filter in your GeoTools code will have the exact same effect. So the short story is, use a Filter to constrain your data, and just let GeoTools do the work.

As you can see from the following class diagram, there are quite a few Filter subinterfaces that can perform tests both on the Feature attributes and geometry. For example, the CompareFilter, LikeFilter and LogicFilter can be used together to create an equivalent of the "where" clause of an SQL statement, whilst the GeometryFilter can check any kind of topological relation with a given reference geometry by leveraging the JTS capabilities, or native operations of a spatial database. The FIDFilter, on the other hand, will check for FID equality or containment in a set of values, just like a constraint on the primary key of a feature.

Again, you will use a FilterFactory to create actual instances of those filters.


Between example

Examples of use (from the Snippets section).

How to use a Compare Filter

Here's the source code needed to create a filter that will, using GeoTools,
find only show cities with a population greater than 100,000, in a shapefile
. In this example we will use the citiesx020.shp file from the National Atlas (www.nationalatlas.gov).
DataStore store = null;
FeatureSource features = null;
FeatureCollection col = null;
FilterFactory filterFactory = FilterFactoryFinder.createFilterFactory();
CompareFilter filter = null;

try {
    store = new ShapefileDataStore(new URL("citiesx020.shp"));
    features = store.getFeatureSource(store.getTypeNames()[0]);
    //count features
    col = features.getFeatures();
    System.out.println("# cities (no filter)= "+col.size());
    //create the filter
    filter = filterFactory.createCompareFilter(CompareFilter.COMPARE_GREATER_THAN);
    FeatureType featureType = features.getFeatures().getSchema();
    filter.addLeftValue(filterFactory.createAttributeExpression("POP_2000"));
    filter.addRightValue(filterFactory.createLiteralExpression(100000));
    //count filtered features
    col = features.getFeatures(filter);
    System.out.println("# cities (after filter)= "+col.size());
} catch (MalformedURLException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (IllegalFilterException e) {
    e.printStackTrace();
}

From Keith Knudsen on the gt2-users lists 18-8-04

Using a bounding box Filter

Icon

This page is out of date - please see:

Given an area of interest stored as an envelope the following code will limit the features returned to those which are not wholy outside the bounding box.

//
// "Where" road BBOX envelope
//
FilterFactory ff = FilterFactoryFinder.createFilterFactory();
Expression bbox = ff.createBBoxExpression( envelope );
Expression geometry = ff.createAttributeExpression( "road" );
GeometryFilter bboxFilter = ff.createGeometryFilter(AbstractFilter.GEOMETRY_BBOX);
bboxFilter.addLeftGeometry( geometry );
bboxFilter.addRightGeometry( bbox );

Of course you may still wonder where "road" comes from - that is the name of the geometry attribute.

This code fetches the default geometry for a typeName.

FeatureType featureType = dataStore.getSchema( typeName );
String geometryName = featureType.getDefaultGeomety().getName();

Note that this may or may not still lead to the datastore reading all of the filters in, for example a shapefile reader will still need to examine all the features to determine which to return. However an SQL based datastore will convert the filter into part of the SQL query which will be much faster.

In GeoTools 2.2, IndexedShapefile is available that will optmize BBOX filters

Between Filter Example

This shows how to create a Between Filter in code. It asks for all features with values between 5 and 15. This could also be done with a logic filter and PropertyIsGreaterThanOrEqualTo and PropertyIsLessThanOrEqualTo filters.
        FilterFactory ff = FilterFactory.createFilterFactory();
        BetweenFilter a= ff.createBetweenFilter();

        AttributeType a1 = attFactory.newAttributeType("value", Integer.class);
        AttributeType a2 = attFactory.newAttributeType("geometry",
                Geometry.class);
        FeatureType schema = FeatureTypeFactory.newFeatureType(new AttributeType[] {
                    a1, a2
                }, "testSchema");

        a.addLeftValue(new LiteralExpressionImpl(new Double(5)));
        a.addRightValue(new LiteralExpressionImpl(new Double(15)));
        a.addMiddleValue(new AttributeExpressionImpl(schema, "value"));

        Feature f1 = schema.create(new Object[] {
                    new Integer(12), new GeometryCollection(null, null, -1)
                });
        Feature f2 = schema.create(new Object[] {
                    new Integer(3), new GeometryCollection(null, null, -1)
                });
        Feature f3 = schema.create(new Object[] {
                    new Integer(15), new GeometryCollection(null, null, -1)
                });
        Feature f4 = schema.create(new Object[] {
                    new Integer(5), new GeometryCollection(null, null, -1)
                });
        Feature f5 = schema.create(new Object[] {
                    new Integer(30), new GeometryCollection(null, null, -1)
                });

        assertEquals(true, a.contains(f1)); // in between
        assertEquals(false, a.contains(f2)); // too small
        assertEquals(true, a.contains(f3)); // max value
        assertEquals(true, a.contains(f4)); // min value
        assertEquals(false, a.contains(f5)); // too large

Create a Filter from XML

Say we have a bit of XML for a filter that we want to parse and get a Filter. First, we need a FilterHandler to receive the Filter from the parser. If we don't need to do anything else at that point, something like the following is sufficient:
SimpleFilterHandler.java
import org.geotools.filter.Filter;
import org.geotools.filter.FilterHandler;
import org.xml.sax.helpers.DefaultHandler;

public class SimpleFilterHandler extends DefaultHandler implements FilterHandler {

    private Filter filter;

    public void filter(Filter filter) {
        this.filter = filter;
    }

    public Filter getFilter() {
        return filter;
    }

}

Then, given an InputSource for the XML, our parse code would look like:

"Parse Method"

public Filter parse(InputSource input) throws IOException, SAXException {
    
    // setup ContentHandler
    SimpleFilterHandler simpleFilterHandler = new SimpleFilterHandler();
    FilterFilter filterFilter = new FilterFilter(simpleFilterHandler, null);
    GMLFilterGeometry filterGeometry = new GMLFilterGeometry(filterFilter);
    GMLFilterDocument filterDocument = new GMLFilterDocument(filterGeometry);

    // parse xml
    XMLReader reader = XMLReaderFactory.createXMLReader();
    reader.setContentHandler(filterDocument);
    reader.parse(input);
    
    return simpleFilterHandler.getFilter();

}