You have an OGC filter with a lot of conditions. When you apply it to your data, you notice that performance drops.

Why do it?

The OGC filter specification supports an elaborate set of filter conditions. You can endlessly combine those filter conditions using boolean and, or, or not conditions. While such combined conditions offer a lot of flexibility, they can also make a filter slow to evaluate. Sometimes, you can use a custom function to reduce the size and complexity of the filter, and increase filter evaluation performance.

Example of a custom function

You want to define a filter that checks whether a property is equal to one of 30 pre-defined numbers. If you rely on the default conditions of the OGC filter specification, you can express this as 30 PropertyIsEqualTo conditions combined through a boolean condition with an or relationship. This combination may result in up to 30 property evaluations per feature when you apply the filter to your data.

Instead, we use a custom function to reduce this combination of conditions to a filter with a single condition. To learn more about this approach, see How to add a custom function to OGC Filter.

We define a contains function with the property and the pre-defined numbers as arguments. This function checks if the property value equals one of the supplied numbers and returns a boolean value indicating the result.

public static class ContainsFunction implements ILcdEvaluatorFunction {
  @Override
  public Object apply(Object[] aArguments, Object aCurrentObject, TLcdOGCFilterContext aOGCFilterContext) {
    // The first argument is the property value, the rest of the arguments represent the list of numbers.
    return Arrays.asList(aArguments).subList(1, aArguments.length).contains(aArguments[0]);
  }

  @Override
  public int getArgumentCount() {
    return Integer.MAX_VALUE;
  }
}

Next, we register the contains function with the OGC filter API.

TLcdOGCFilterEvaluator.registerDefaultFunction(TLcdXMLName.getInstance(new QName("contains")), new ContainsFunction());

We finish by creating a filter with a single condition. This filter compares the result of the custom function with the boolean value true.

// Define the list of arguments for the function. The first argument is the property name that we want to compare,
// the other arguments are the numbers to compare with.
List<ILcdOGCExpression> expressions = new ArrayList<>();
expressions.add(TLcdOGCFilterFactory.property(propertyName));
expressions.addAll(list.stream().map(TLcdOGCFilterFactory::literal).collect(Collectors.toList()));
// Create the filter relying on the custom function.
TLcdOGCFunction containsFunction = TLcdOGCFilterFactory.function("contains", expressions.toArray(new ILcdOGCExpression[0]));
TLcdOGCFilter filter = new TLcdOGCFilter(TLcdOGCFilterFactory.eq(containsFunction, TLcdOGCFilterFactory.literal(true)));

Compared with the 30 PropertyIsEqualTo conditions, this filter with just one condition is much faster to evaluate.