blob: 8f90dbdbc272401395c15645da569c937feb17dd [file]
= Using Continuous Queries
:javaFile: {javaCodeDir}/UsingContinuousQueries.java
A continuous query is a query that monitors data modifications occurring in a cache.
Once a continuous query is started, you get notified of all the data changes that fall into your query filter.
All update events are propagated to the <<Local Listener,local listener>> that must be registered in the query.
Continuous query implementation guarantees exactly once delivery of an event to the local listener.
You can also specify a remote filter to narrow down the range of entries that are monitored for updates.
[CAUTION]
====
[discrete]
=== Continuous Queries and MVCC
Continuous queries have a number of link:transactions/mvcc[functional limitations] when used with MVCC-enabled caches.
====
== Local Listener
When a cache gets modified (an entry is inserted, updated, or deleted), an event is sent to the continuous query's local listener so that your application can react accordingly.
The local listener is executed on the node that initiated the query.
Note that the continuous query throws an exception if started without a local listener.
[tabs]
--
tab:Java[]
[source,java]
----
include::{javaFile}[tag=localListener,indent=0]
----
tab:C#/.NET[]
[source,csharp]
----
include::code-snippets/dotnet/ContiniuosQueries.cs[tag=localListener,indent=0]
----
tab:C++[]
[source,cpp]
----
include::code-snippets/cpp/src/continuous_query_listener.cpp[tag=continuous-query-listener,indent=0]
----
--
== Initial Query
You can specify an initial query that is executed before the continuous query gets registered in the cluster and before you start to receive updates.
To specify an initial query, use the `ContinuousQuery.setInitialQuery(...)` method.
Just like scan queries, a continuous query is executed via the `query()` method that returns a cursor. When an initial query is set, you can use that cursor to iterate over the results of the initial query.
[tabs]
--
tab:Java[]
[source,java]
----
include::{javaFile}[tag=initialQry,indent=0]
----
tab:C#/.NET[unsupported]
tab:C++[]
[source,cpp]
----
include::code-snippets/cpp/src/continuous_query.cpp[tag=continuous-query,indent=0]
----
--
== Remote Filter
This filter is executed for each updated key and evaluates whether the update should be propagated to the query's local listener.
If the filter returns `true`, then the local listener is notified about the update.
For redundancy reasons, the filter is executed for both primary and backup versions (if backups are configured) of the key.
Because of this, a remote filter can be used as a remote listener for update events.
[tabs]
--
tab:Java[]
[source,java]
----
include::{javaFile}[tag=remoteFilter,indent=0]
----
tab:C#/.NET[]
[source,csharp]
----
include::code-snippets/dotnet/ContiniuosQueries.cs[tag=remoteFilter,indent=0]
----
tab:C++[]
[source,cpp]
----
include::code-snippets/cpp/src/continuous_query_filter.cpp[tag=continuous-query-filter,indent=0]
----
--
[NOTE]
====
In order to use remote filters, make sure the class definitions of the filters are available on the server nodes.
You can do this in two ways:
* Add the classes to the classpath of every server node;
* link:code-deployment/peer-class-loading[Enable peer class loading].
====
== Remote Transformer
By default, continuous queries send the whole updated object to the local listener. This can lead to excessive network usage, especially if the object is very large. Moreover, applications often need only a subset of fields of the object.
To address these cases, you can use a continuous query with a transformer. A transformer is a function that is executed on remote nodes for every updated object and sends back only the results of the transformation.
[tabs]
--
tab:Java[]
[source,java]
----
include::{javaFile}[tag=transformer,indent=0]
----
tab:C#/.NET[unsupported]
tab:C++[unsupported]
--
[NOTE]
====
In order to use transformers, make sure the class definitions of the transformers are available on the server nodes.
You can do this in two ways:
* Add the classes to the classpath of every server node;
* link:code-deployment/peer-class-loading[Enable peer class loading].
====
== Examples
The following application examples show typical usage of continuous queries.
link:{githubUrl}/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheContinuousQueryExample.java[CacheContinuousQueryExample.java,window=_blank]
link:{githubUrl}/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheContinuousAsyncQueryExample.java[CacheContinuousAsyncQueryExample.java,window=_blank]
link:{githubUrl}/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheContinuousQueryWithTransformerExample.java[CacheContinuousQueryWithTransformerExample.java,window=_blank]