This is an automated email from the ASF dual-hosted git repository.

namelchev pushed a commit to branch ignite-2.12
in repository https://gitbox.apache.org/repos/asf/ignite.git

commit 21dcf477459ce9f336eae7fbb288b60ed22bbb75
Author: Maksim Timonin <timonin.ma...@gmail.com>
AuthorDate: Tue Nov 9 12:28:35 2021 +0300

    IGNITE-15745 Add docs for IndexQuery (#9545)
    
    (cherry picked from commit 025cc9fbf5553e7fbc81f8e94326a34743ad73fc)
---
 docs/_data/toc.yaml                                |  4 +-
 docs/_docs/code-deployment/peer-class-loading.adoc |  4 +-
 .../apache/ignite/snippets/UsingScanQueries.java   | 75 ++++++++++++++++++++++
 .../collocated-computations.adoc                   |  2 +-
 docs/_docs/events/events.adoc                      |  6 +-
 ...-scan-queries.adoc => using-cache-queries.adoc} | 60 ++++++++++++++++-
 docs/_docs/thin-clients/java-thin-client.adoc      |  6 +-
 .../examples/datagrid/CacheQueryExample.java       | 50 ++++++++++++++-
 .../org/apache/ignite/examples/model/Person.java   |  9 ++-
 .../org/apache/ignite/cache/query/IndexQuery.java  |  9 ++-
 10 files changed, 206 insertions(+), 19 deletions(-)

diff --git a/docs/_data/toc.yaml b/docs/_data/toc.yaml
index a4881c7..e57c9fb 100644
--- a/docs/_data/toc.yaml
+++ b/docs/_data/toc.yaml
@@ -177,8 +177,8 @@
       url: key-value-api/basic-cache-operations
     - title: Working with Binary Objects
       url: key-value-api/binary-objects
-    - title: Using Scan Queries
-      url: key-value-api/using-scan-queries
+    - title: Using Cache Queries
+      url: key-value-api/using-cache-queries
     - title: Read Repair
       url: read-repair
 - title: Performing Transactions
diff --git a/docs/_docs/code-deployment/peer-class-loading.adoc 
b/docs/_docs/code-deployment/peer-class-loading.adoc
index 0dd7d18..3781faa 100644
--- a/docs/_docs/code-deployment/peer-class-loading.adoc
+++ b/docs/_docs/code-deployment/peer-class-loading.adoc
@@ -28,12 +28,12 @@ If you develop C# and .NET applications, then refer to the 
link:net-specific/net
 page for details on how to set up and use the peer-class-loading feature with 
that type of applications.
 ====
 
-For example, when link:key-value-api/using-scan-queries[querying data] with a 
custom transformer, you only need to define your tasks on the client node that 
initiates the computation, and Ignite loads the classes to the server nodes.
+For example, when link:key-value-api/using-cache-queries[querying data] with a 
custom transformer, you just need to define your tasks on the client node that 
initiates the computation, and Ignite will upload the classes to the server 
nodes.
 
 When enabled, peer class loading is used to deploy the following classes:
 
 * Tasks and jobs submitted via the 
link:distributed-computing/distributed-computing[compute interface].
-* Transformers and filters used with 
link:key-value-api/using-scan-queries[scan queries] and 
link:key-value-api/continuous-queries[continuous queries].
+* Transformers and filters used with 
link:key-value-api/using-cache-queries[cache queries] and 
link:key-value-api/continuous-queries[continuous queries].
 * Stream transformers, receivers and visitors used with 
link:data-streaming#data-streamers[data streamers].
 * link:distributed-computing/collocated-computations#entry-processor[Entry 
processors].
 
diff --git 
a/docs/_docs/code-snippets/java/src/main/java/org/apache/ignite/snippets/UsingScanQueries.java
 
b/docs/_docs/code-snippets/java/src/main/java/org/apache/ignite/snippets/UsingScanQueries.java
index 49a9f53..e14668b 100644
--- 
a/docs/_docs/code-snippets/java/src/main/java/org/apache/ignite/snippets/UsingScanQueries.java
+++ 
b/docs/_docs/code-snippets/java/src/main/java/org/apache/ignite/snippets/UsingScanQueries.java
@@ -16,17 +16,28 @@
  */
 package org.apache.ignite.snippets;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.List;
 import javax.cache.Cache;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.Ignition;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.QueryIndexType;
+import org.apache.ignite.cache.query.IndexQuery;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.ScanQuery;
+import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.lang.IgniteClosure;
 import org.junit.jupiter.api.Test;
 
+import static org.apache.ignite.cache.query.IndexQueryCriteriaBuilder.eq;
+import static org.apache.ignite.cache.query.IndexQueryCriteriaBuilder.gt;
+
 public class UsingScanQueries {
 
     @Test
@@ -84,4 +95,68 @@ public class UsingScanQueries {
             System.out.println("Transformer example output:" + keys.get(0));
         }
     }
+
+    @Test
+    void executingIndexQueriesExample() {
+        try (Ignite ignite = Ignition.start()) {
+            //tag::idxQry[]
+            // Create index by 2 fields (orgId, salary).
+            QueryEntity personEntity = new QueryEntity(Integer.class, 
Person.class)
+                .setFields(new LinkedHashMap<String, String>() {{
+                    put("orgId", Integer.class.getName());
+                    put("salary", Integer.class.getName());
+                }})
+                .setIndexes(Collections.singletonList(
+                    new QueryIndex(Arrays.asList("orgId", "salary"), 
QueryIndexType.SORTED)
+                        .setName("ORG_SALARY_IDX")
+                ));
+
+            CacheConfiguration<Integer, Person> ccfg = new 
CacheConfiguration<Integer, Person>("entityCache")
+                .setQueryEntities(Collections.singletonList(personEntity));
+
+            IgniteCache<Integer, Person> cache = ignite.getOrCreateCache(ccfg);
+
+            //end::idxQry[]
+            {
+            //tag::idxQry[]
+            // Find the persons who work in Organization 1.
+            QueryCursor<Cache.Entry<Integer, Person>> cursor = cache.query(
+                new IndexQuery<Integer, Person>(Person.class, "ORG_SALARY_IDX")
+                    .setCriteria(eq("orgId", 1))
+            );
+            //end::idxQry[]
+            }
+
+            {
+                //tag::idxQryMultipleCriteria[]
+                // Find the persons who work in Organization 1 and have salary 
more than 1,000.
+                QueryCursor<Cache.Entry<Integer, Person>> cursor = cache.query(
+                    new IndexQuery<Integer, Person>(Person.class, 
"ORG_SALARY_IDX")
+                        .setCriteria(eq("orgId", 1), gt("salary", 1000))
+                );
+                //end::idxQryMultipleCriteria[]
+            }
+
+            {
+                //tag::idxQryNoIdxName[]
+                // Ignite finds suitable index "ORG_SALARY_IDX" by specified 
criterion field "orgId".
+                QueryCursor<Cache.Entry<Integer, Person>> cursor = cache.query(
+                    new IndexQuery<Integer, Person>(Person.class)
+                        .setCriteria(eq("orgId", 1))
+                );
+                //end::idxQryNoIdxName[]
+            }
+
+            {
+                //tag::idxQryFilter[]
+                // Find the persons who work in Organization 1 and whose name 
contains 'Vasya'.
+                QueryCursor<Cache.Entry<Integer, Person>> cursor = cache.query(
+                    new IndexQuery<Integer, Person>(Person.class)
+                        .setCriteria(eq("orgId", 1))
+                        .setFilter((k, v) -> v.getName().contains("Vasya"))
+                );
+                //end::idxQryFilter[]
+            }
+        }
+    }
 }
diff --git a/docs/_docs/distributed-computing/collocated-computations.adoc 
b/docs/_docs/distributed-computing/collocated-computations.adoc
index 47bd72f..03daeb6 100644
--- a/docs/_docs/distributed-computing/collocated-computations.adoc
+++ b/docs/_docs/distributed-computing/collocated-computations.adoc
@@ -105,7 +105,7 @@ tab:C++[unsupported]
 ====
 [discrete]
 === Performance Considerations
-Colocated computations yield performance benefits when the amount of the data 
you want to process is sufficiently large. In some cases, when the amount of 
data is small, a link:key-value-api/using-scan-queries[scan query] may perform 
better.
+Colocated computations yield performance benefits when the amount of the data 
you want to process is sufficiently large. In some cases, when the amount of 
data is small, a link:key-value-api/using-cache-queries[scan query] may perform 
better.
 
 ====
 
diff --git a/docs/_docs/events/events.adoc b/docs/_docs/events/events.adoc
index 3f7da30..cc08413 100644
--- a/docs/_docs/events/events.adoc
+++ b/docs/_docs/events/events.adoc
@@ -128,9 +128,9 @@ Cache events are also generated when you use DML commands.
 
 | EVT_CACHE_OBJECT_READ
 | An object is read from a cache.
-This event is not emitted when you use 
link:key-value-api/using-scan-queries[scan queries] (use <<Cache Query Events>> 
to monitor scan queries).
+This event is not emitted when you use 
link:key-value-api/using-cache-queries[scan queries] (use <<Cache Query 
Events>> to monitor scan queries).
 | The node where read operation is executed.
-It can be either the primary or backup node (the latter case is only possible 
when link:configuring-caches/configuration-overview#readfrombackup[reading from 
backups is enabled]).
+It can be either the primary or backup node (the latter case is only possible 
when link:configuring-caches/configuration-overview#readfrombackup[reading from 
backups] is enabled).
 In transactional caches, the event can be generated on both the primary and 
backup nodes depending on the concurrency and isolation levels.
 
 | EVT_CACHE_OBJECT_REMOVED | An object is removed from a cache. |The primary 
and backup nodes for the entry.
@@ -171,7 +171,7 @@ There are two types of events that are related to cache 
queries:
 [cols="2,5,3",opts="header"]
 |===
 | Event Type | Event Description | Where Event Is Fired
-| EVT_CACHE_QUERY_OBJECT_READ | An object is read as part of a query 
execution. This event is generated for every object that matches the 
link:key-value-api/using-scan-queries#executing-scan-queries[query filter]. | 
The primary node of the object that is read.
+| EVT_CACHE_QUERY_OBJECT_READ | An object is read as part of a query 
execution. This event is generated for every object that matches the 
link:key-value-api/using-cache-queries#executing-scan-queries[query filter]. | 
The primary node of the object that is read.
 | EVT_CACHE_QUERY_EXECUTED  |  This event is generated when a query is 
executed. | All server nodes that host the cache.
 |===
 
diff --git a/docs/_docs/key-value-api/using-scan-queries.adoc 
b/docs/_docs/key-value-api/using-cache-queries.adoc
similarity index 62%
rename from docs/_docs/key-value-api/using-scan-queries.adoc
rename to docs/_docs/key-value-api/using-cache-queries.adoc
index 5463e6f..f7f8035 100644
--- a/docs/_docs/key-value-api/using-scan-queries.adoc
+++ b/docs/_docs/key-value-api/using-cache-queries.adoc
@@ -12,7 +12,7 @@
 // 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.
-= Using Scan Queries
+= Using Cache Queries
 
 :javaFile: {javaCodeDir}/UsingScanQueries.java
 :dotnetFile: code-snippets/dotnet/UsingScanQueries.cs
@@ -20,6 +20,7 @@
 
 == Overview
 `IgniteCache` has several query methods, all of which receive a subclass of 
the `Query` class and return a `QueryCursor`.
+Available types of queries: `ScanQuery`, `IndexQuery`, `TextQuery`.
 
 A `Query` represents an abstract paginated query to be executed on a cache.
 The page size is configurable via the `Query.setPageSize(...)` method (default 
is 1024).
@@ -118,7 +119,64 @@ 
include::code-snippets/cpp/src/scan_query.cpp[tag=set-local,indent=0]
 ----
 --
 
+== Executing Index Queries
+
+[WARNING]
+====
+[discrete]
+Experimental API. Introduced since Apache Ignite 2.12. Only Java API is 
supported. Please send your questions and bug reports
+to u...@ignite.apache.org.
+====
+
+Index queries work over distributed indexes and retrieve cache entries that 
match the specified query. `QueryCursor`
+delivers sorted cache entries by the order defined for queried index. 
`IndexQuery` can be used if a low amount of data
+matches filtering criteria. For such cases, `ScanQuery` usage is not optimal: 
it firstly extracts all cache entries and
+then applies a filter to them. `IndexQuery` relies on index tree structure and 
filters most of the entries without extracting.
+
+[source,java]
+----
+include::{javaFile}[tag=idxQry,indent=0]
+----
+
+Index query criteria are defined in `IndexQueryCriteriaBuilder`. The goal of 
the criteria is to build a valid range to
+traverse the index tree. For this reason, criteria fields have to match the 
specified index. For example, if there is an
+index defined with (A, B) set, then valid criteria sets are (A) and (A, B). 
Criteria with the single (B) field are invalid
+because the field (B) is not a prefix set of the specified index fields, and 
it's impossible to build a narrow index range
+with it.
+
+[NOTE]
+====
+Criteria are joined by the AND operator. It is also possible to use multiple 
criteria for the same field.
+====
+
+[source,java]
+----
+include::{javaFile}[tag=idxQryMultipleCriteria,indent=0]
+----
+
+The index name is an optional parameter. In this case, Ignite tries to figure 
out the index by itself using specified criteria fields.
+
+[source,java]
+----
+include::{javaFile}[tag=idxQryNoIdxName,indent=0]
+----
+
+For the empty criteria list, a full scan of the specified index is performed. 
If index name is also not specified, then the
+PrimaryKey index is used.
+
+=== Additional filtering
+
+`IndexQuery` also supports an optional predicate, the same as `ScanQuery` has. 
It's suitable for additional cache entry
+filtering in cases when a filter doesn't match an index tree range. For 
example, it contains some logic, the "OR"
+operations, or fields that are not the part of the index.
+
+[source,java]
+----
+include::{javaFile}[tag=idxQryFilter,indent=0]
+----
+
 == Related Topics
 
 * link:restapi#sql-scan-query-execute[Execute scan query via REST API]
 * link:events/events#cache-query-events[Cache Query Events]
+* link:SQL/indexes[Defining Indexes]
diff --git a/docs/_docs/thin-clients/java-thin-client.adoc 
b/docs/_docs/thin-clients/java-thin-client.adoc
index b71d15a..2f71720 100644
--- a/docs/_docs/thin-clients/java-thin-client.adoc
+++ b/docs/_docs/thin-clients/java-thin-client.adoc
@@ -132,9 +132,9 @@ include::{sourceCodeFile}[tag=key-value-operations,indent=0]
 -------------------------------------------------------------------------------
 
 === Executing Scan Queries
-Use the `ScanQuery<K, V>` class to get a set of entries that satisfy a given 
condition. The thin client sends the query to the cluster node where it is 
executed as a normal link:key-value-api/using-scan-queries[scan query].
+Use the `ScanQuery<K, V>` class to get a set of entries that satisfy a given 
condition. The thin client sends the query to the cluster node where it is 
executed as a regular link:key-value-api/using-cache-queries[scan query].
 
-The query condition is specified by an `IgniteBiPredicate<K, V>` object that 
is passed to the query constructor as an argument. The predicate is applied on 
the server side. If you don't provide any predicate, the query returns all 
cache entries.
+The query condition is specified by an `IgniteBiPredicate<K, V>` object that 
is passed to the query constructor as an argument. The predicate is applied on 
the server side. If there is no predicate provided, the query returns all cache 
entries.
 
 NOTE: The classes of the predicates must be available on the server nodes of 
the cluster.
 
@@ -379,4 +379,4 @@ include::{sourceCodeFile}[tag=async-api,indent=0]
 
 * Async methods do not block the calling thread
 * Async methods return `IgniteClientFuture<T>` which is a combination of 
`Future<T>` and `CompletionStage<T>`.
-* Async continuations are executed using 
`ClientConfiguration.AsyncContinuationExecutor`, which defaults to 
`ForkJoinPool#commonPool()`. For example, `cache.getAsync(1).thenAccept(val -> 
System.out.println(val))` will execute the `println` call using a thread from 
the `commonPool`.
\ No newline at end of file
+* Async continuations are executed using 
`ClientConfiguration.AsyncContinuationExecutor`, which defaults to 
`ForkJoinPool#commonPool()`. For example, `cache.getAsync(1).thenAccept(val -> 
System.out.println(val))` will execute the `println` call using a thread from 
the `commonPool`.
diff --git 
a/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheQueryExample.java
 
b/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheQueryExample.java
index c486a5c..0a9838a 100644
--- 
a/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheQueryExample.java
+++ 
b/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheQueryExample.java
@@ -24,6 +24,7 @@ import org.apache.ignite.Ignition;
 import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cache.affinity.AffinityKey;
+import org.apache.ignite.cache.query.IndexQuery;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.ScanQuery;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
@@ -34,8 +35,11 @@ import org.apache.ignite.examples.model.Organization;
 import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.lang.IgniteBiPredicate;
 
+import static org.apache.ignite.cache.query.IndexQueryCriteriaBuilder.eq;
+import static org.apache.ignite.cache.query.IndexQueryCriteriaBuilder.gt;
+
 /**
- * Cache queries example. This example demonstrates TEXT and FULL SCAN
+ * Cache queries example. This example demonstrates TEXT, FULL SCAN and INDEX
  * queries over cache.
  * <p>
  * Example also demonstrates usage of fields queries that return only required
@@ -104,6 +108,9 @@ public class CacheQueryExample {
 
                 // Example for TEXT-based querying for a given string in 
peoples resumes.
                 textQuery();
+
+                // Example for INDEX-based query with index criteria.
+                indexQuery();
             }
             finally {
                 // Distributed cache could be removed from cluster only by 
Ignite.destroyCache() call.
@@ -153,6 +160,47 @@ public class CacheQueryExample {
     }
 
     /**
+     * Example for query indexes with criteria and binary objects.
+     */
+    private static void indexQuery() {
+        IgniteCache<Long, Person> cache = 
Ignition.ignite().cache(PERSON_CACHE);
+
+        // Query for all people who work in the organization "ApacheIgnite".
+        QueryCursor<Cache.Entry<Long, Person>> igniters = cache.query(
+            new IndexQuery<Long, Person>(Person.class)
+                .setCriteria(eq("orgId", 1L))
+        );
+
+        print("Following people work in the 'ApacheIgnite' organization 
(queried with INDEX query): ",
+            igniters.getAll());
+
+        // Query for all people who work in the organization "Other" and have 
salary more than 1,500.
+        QueryCursor<Cache.Entry<Long, Person>> others = cache.query(
+            new IndexQuery<Long, Person>(Person.class)  // Index name {@link 
Person#ORG_SALARY_IDX} is optional.
+                .setCriteria(eq("orgId", 2L), gt("salary", 1500.0)));
+
+        print("Following people work in the 'Other' organizations and have 
salary more than 1500 (queried with INDEX query): ",
+            others.getAll());
+
+        // Query for all people who have salary more than 1,500 using 
BinaryObject.
+        QueryCursor<Cache.Entry<BinaryObject, BinaryObject>> rich = 
cache.withKeepBinary().query(
+            new IndexQuery<BinaryObject, BinaryObject>(Person.class.getName())
+                .setCriteria(gt("salary", 1500.0)));
+
+        print("Following people have salary more than 1500 (queried with INDEX 
query and using binary objects): ",
+            rich.getAll());
+
+        // Query for all people who have salary more than 1,500 and have 
'Master Degree' in their resumes.
+        QueryCursor<Cache.Entry<BinaryObject, BinaryObject>> richMasters = 
cache.withKeepBinary().query(
+            new IndexQuery<BinaryObject, BinaryObject>(Person.class.getName())
+                .setCriteria(gt("salary", 1500.0))
+                .setFilter((k, v) -> 
v.<String>field("resume").contains("Master")));
+
+        print("Following people have salary more than 1500 and Master degree 
(queried with INDEX query): ",
+            richMasters.getAll());
+    }
+
+    /**
      * Populate cache with test data.
      */
     private static void initialize() {
diff --git 
a/examples/src/main/java/org/apache/ignite/examples/model/Person.java 
b/examples/src/main/java/org/apache/ignite/examples/model/Person.java
index 6d3a6df..29a2d9d 100644
--- a/examples/src/main/java/org/apache/ignite/examples/model/Person.java
+++ b/examples/src/main/java/org/apache/ignite/examples/model/Person.java
@@ -30,12 +30,15 @@ public class Person implements Serializable {
     /** */
     private static final AtomicLong ID_GEN = new AtomicLong();
 
+    /** Name of index by two fields (orgId, salary). */
+    public static final String ORG_SALARY_IDX = "ORG_SALARY_IDX";
+
     /** Person ID (indexed). */
     @QuerySqlField(index = true)
     public Long id;
 
     /** Organization ID (indexed). */
-    @QuerySqlField(index = true)
+    @QuerySqlField(index = true, orderedGroups = @QuerySqlField.Group(name = 
ORG_SALARY_IDX, order = 0))
     public Long orgId;
 
     /** First name (not-indexed). */
@@ -51,10 +54,10 @@ public class Person implements Serializable {
     public String resume;
 
     /** Salary (indexed). */
-    @QuerySqlField(index = true)
+    @QuerySqlField(index = true, orderedGroups = @QuerySqlField.Group(name = 
ORG_SALARY_IDX, order = 1))
     public double salary;
 
-    /** Custom cache key to guarantee that person is always collocated with 
its organization. */
+    /** Custom cache key to guarantee that person is always colocated with its 
organization. */
     private transient AffinityKey<Long> key;
 
     /**
diff --git 
a/modules/core/src/main/java/org/apache/ignite/cache/query/IndexQuery.java 
b/modules/core/src/main/java/org/apache/ignite/cache/query/IndexQuery.java
index 25f7807..1c059eb 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/query/IndexQuery.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/query/IndexQuery.java
@@ -29,12 +29,15 @@ import org.apache.ignite.lang.IgniteExperimental;
 import org.jetbrains.annotations.Nullable;
 
 /**
- * Index query runs over internal index structure and returns cache entries 
for index rows.
+ * Index queries work over distributed indexes and retrieve cache entries that 
match the specified criteria.
+ * {@code QueryCursor} delivers sorted cache entries by the order defined for 
queried index.
  *
- * {@code IndexQuery} has to be initialized with cache value class or type. 
The algorithm of discovering index is as following:
+ * {@code IndexQuery} has to be initialized with cache value class or type. 
The algorithm of discovering index is as follows:
  * 1. If {@link #idxName} is set, then use it.
  * 2. If {@link #idxName} is not set, then find an index that matches criteria 
fields.
- * 3. If neither of {@link #idxName} or {@link #setCriteria(List)} used, then 
perform index scan over PK index for specified Value type.
+ * 3. If neither {@link #idxName}, nor {@link #setCriteria(List)} is used, 
then perform index scan over PK index for specified Value type.
+ *
+ * Conjuction of items in {@link #criteria} has to represent a valid range to 
traverse the index tree.
  */
 @IgniteExperimental
 public final class IndexQuery<K, V> extends Query<Cache.Entry<K, V>> {

Reply via email to