This repository provides a reusable, tested, and solid implementation of a CXF visitor that can take a pre-parsed FIQL AST and generate an Elasticsearch QueryBuilder. Given an expression, you can output a QueryBuilder that can be used with the standard Elasticsearch Java SearchRequestBuilder.
The work in this repository is licensed under the Apache 2.0 License. Please see the repository's LICENSE
file for details.
FIQL is a standard URI-friendly way of expressing a filter across a collection of items. You can consider this something like generating a SQL where
clause. Apache CXF provides an implementation of FIQL that it calls JAX-RS Search.
The default implementation of JAX-RS Search includes a few visitors:
- HBase
- JPA
- LDAP
- Lucene
- OData
$filter
clauses - SQL
Note that most of the above are not fully-featured search visitors, but instead their output approximates something like a where
clause or filter. In the case of OData, this is explicitly obvious as JAX-RS implements only $filter
.
Unlike most of these implementations (excepting Lucene, which is what ES is built upon), Elasticsearch is a fully-featured search product, and includes other functionality such as aggregation and various scripts. Please note that this library makes no attempt to handle aggregation, faceting, percolation etc. This only provides you with query
params.
This artifact is currently unavailable in the Maven Central repository, or other open source repositories. You will want to cache this in a local Nexus/Artifactory and add it to your pom.xml
:
<dependency>
<groupId>com._8x8.cloud.platform</groupId>
<artifactId>fiql-elasticsearch</artifactId>
<version>1.0.16-a1e014d6</version>
</dependency>
mvn clean install
If you are using another JAX-RS implementation, such as Jersey or RESTEasy you may run into issues depending on how lucky you are with your classloader order. If you'd like to ensure that you keep using your JAX-RS provider rather than CXF, you'll want to add a META-INF/services/javax.ws.rs.ext.RuntimeDelegate
file to denote your RuntimeDelegate. An example for Jersey 2.x would be:
org.glassfish.jersey.server.internal.RuntimeDelegateImpl
This tells the JAX-RS libraries which implementation's factories to use to bootstrap your application.
Want to know more?
We've tried to keep the dependency tree as simple as possible, leaking as few transitive dependencies as possible. It may be (will be) the case that we've messed this up. File a pull request, help us get it right!
Check out the ElasticsearchQueryBuilderVisitorIT
or the JAX-RS Search docs.
Want a more streamlined experience? Check out the ElasticsearchQueryBuilderIT
.
If you read the JAX-RS Search page carefully you'll note that the functionality it support highly depends on what implementation you're using. Here are some relevant notes.
This visitor is not threadsafe by design. This may seem somewhat stupid, but if you take a look at what a visitor does it doesn't really make sense to re-use them. All the state they contain is specific to the parsed expression being evaluated. Rather than attempting to use the somewhat scary thread safety primitives in JAX-RS Search, use this visitor like a prototype, and not a singleton.
Unlike the SQLPrinterVisitor the ElasticsearchQueryBuilderVisitor
supports collections.
If you have something that looks like this:
import java.util.ArrayList;
import java.util.List;
public class TagCollections {
private List<String> tags = new ArrayList<>();
public List<String> getTags() {
return tags;
}
public void setTags(final List<String> tags) {
this.tags = tags;
}
}
You can look for an item with a tag of "foo" via the following FIQL:
tags==foo
Please note that count
queries are not supported, and will throw an IllegalArgumentException
. These continue to be supported solely by JPA.
Case sensitivity in Elasticsearch is a bit more complicated than SQL. While the FIQL specification states that all searches will be case-insensitive, this depends entirely on your Elasticsearch mappings. If you need case-insensitive search, you'll need to use the case-insensitive analyzer.
Wildcards of *
are supported for both the ==
and !=
operators as a standard Elasticsearch wildcard query.
This visitor does not handle the special case of null (or not-null) checks, nor for the detection of truthiness. Some of the other custom visitors may do so, and we can add it here if required.
Unlike some of the other visitors, this one does not support field alias mapping. We can add this feature if folks need it, but it's hard to understand how it would work with Elasticsearch without an example.
By default, the FIQL parsers support a date format of yyyy-MM-DD
, without time. If you try and pass epoch/epoch+millis format, it will break. It is recommended that you use numeric mappings for these fields.
Conversely, output to the Elasticsearch query will also be in the same date format.