blob: f3b99791e2d6247cc0e921d623a0668d39229250 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
*/
package org.apache.ignite.examples.sql;
import java.util.List;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.Ignition;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.cache.affinity.AffinityKey;
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.examples.ExampleNodeStartup;
import org.apache.ignite.examples.model.Organization;
import org.apache.ignite.examples.model.Person;
/**
* SQL queries example with the usage of Java SQL API.
* <p>
* Example also demonstrates usage of fields queries that return only required
* fields instead of whole key-value pairs. When fields queries are distributed
* across several nodes, they may not work as expected. Keep in mind following
* limitations (not applied if data is queried from one node only):
* <ul>
* <li>
* Non-distributed joins will work correctly only if joined objects are stored in
* collocated mode. Refer to {@link AffinityKey} javadoc for more details.
* <p>
* To use distributed joins it is necessary to set query 'distributedJoin' flag using
* {@link SqlFieldsQuery#setDistributedJoins(boolean)}.
* </li>
* <li>
* Note that if you created query on to replicated cache, all data will
* be queried only on one node, not depending on what caches participate in
* the query (some data from partitioned cache can be lost). And visa versa,
* if you created it on partitioned cache, data from replicated caches
* will be duplicated.
* </li>
* </ul>
* <p>
* Remote nodes should be started using {@link ExampleNodeStartup} which will
* start node with {@code examples/config/example-ignite.xml} configuration.
*/
public class SqlQueriesExample {
/** Organizations cache name. */
private static final String ORG_CACHE = SqlQueriesExample.class.getSimpleName() + "Organizations";
/** Persons collocated with Organizations cache name. */
private static final String COLLOCATED_PERSON_CACHE = SqlQueriesExample.class.getSimpleName() + "CollocatedPersons";
/** Persons cache name. */
private static final String PERSON_CACHE = SqlQueriesExample.class.getSimpleName() + "Persons";
/**
* Executes example.
*
* @param args Command line arguments, none required.
* @throws Exception If example execution failed.
*/
public static void main(String[] args) throws Exception {
try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
System.out.println();
System.out.println(">>> SQL queries example started.");
CacheConfiguration<Long, Organization> orgCacheCfg = new CacheConfiguration<>(ORG_CACHE);
orgCacheCfg.setCacheMode(CacheMode.PARTITIONED); // Default.
orgCacheCfg.setIndexedTypes(Long.class, Organization.class);
CacheConfiguration<AffinityKey<Long>, Person> colPersonCacheCfg =
new CacheConfiguration<>(COLLOCATED_PERSON_CACHE);
colPersonCacheCfg.setCacheMode(CacheMode.PARTITIONED); // Default.
colPersonCacheCfg.setIndexedTypes(AffinityKey.class, Person.class);
CacheConfiguration<Long, Person> personCacheCfg = new CacheConfiguration<>(PERSON_CACHE);
personCacheCfg.setCacheMode(CacheMode.PARTITIONED); // Default.
personCacheCfg.setIndexedTypes(Long.class, Person.class);
try {
// Create caches.
ignite.getOrCreateCache(orgCacheCfg);
ignite.getOrCreateCache(colPersonCacheCfg);
ignite.getOrCreateCache(personCacheCfg);
// Populate caches.
initialize();
// Example for SQL-based querying employees based on salary ranges.
sqlQuery();
// Example for SQL-based querying employees for a given organization
// (includes SQL join for collocated objects).
sqlQueryWithJoin();
// Example for SQL-based querying employees for a given organization
// (includes distributed SQL join).
sqlQueryWithDistributedJoin();
// Example for SQL-based querying to calculate average salary
// among all employees within a company.
sqlQueryWithAggregation();
// Example for SQL-based fields queries that return only required
// fields instead of whole key-value pairs.
sqlFieldsQuery();
// Example for SQL-based fields queries that uses joins.
sqlFieldsQueryWithJoin();
}
finally {
// Distributed cache could be removed from cluster only by Ignite.destroyCache() call.
ignite.destroyCache(COLLOCATED_PERSON_CACHE);
ignite.destroyCache(PERSON_CACHE);
ignite.destroyCache(ORG_CACHE);
}
print("SQL queries example finished.");
}
}
/**
* Example for SQL queries based on salary ranges.
*/
private static void sqlQuery() {
IgniteCache<Long, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
// SQL clause which selects salaries based on range.
// Extract fields of the entry.
String sql = "select * from Person where salary > ? and salary <= ?";
// Execute queries for salary ranges.
print("People with salaries between 0 and 1000 (queried with SQL query): ",
cache.query(new SqlFieldsQuery(sql).setArgs(0, 1000)).getAll());
print("People with salaries between 1000 and 2000 (queried with SQL query): ",
cache.query(new SqlFieldsQuery(sql).setArgs(1000, 2000)).getAll());
}
/**
* Example for SQL queries based on all employees working for a specific organization.
*/
private static void sqlQueryWithJoin() {
IgniteCache<AffinityKey<Long>, Person> cache = Ignition.ignite().cache(COLLOCATED_PERSON_CACHE);
// SQL clause query which joins on 2 types to select people for a specific organization.
String joinSql =
"select pers.* from Person as pers, \"" + ORG_CACHE + "\".Organization as org " +
"where pers.orgId = org.id " +
"and lower(org.name) = lower(?)";
// Execute queries for find employees for different organizations.
print("Following people are 'ApacheIgnite' employees: ",
cache.query(new SqlFieldsQuery(joinSql).setArgs("ApacheIgnite")).getAll());
print("Following people are 'Other' employees: ",
cache.query(new SqlFieldsQuery(joinSql).setArgs("Other")).getAll());
}
/**
* Example for SQL queries based on all employees working
* for a specific organization (query uses distributed join).
*/
private static void sqlQueryWithDistributedJoin() {
IgniteCache<Long, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
// SQL clause query which joins on 2 types to select people for a specific organization.
String joinSql =
"select pers.* from Person as pers, \"" + ORG_CACHE + "\".Organization as org " +
"where pers.orgId = org.id " +
"and lower(org.name) = lower(?)";
SqlFieldsQuery qry = new SqlFieldsQuery(joinSql).setArgs("ApacheIgnite");
// Enable distributed joins for query.
qry.setDistributedJoins(true);
// Execute queries for find employees for different organizations.
print("Following people are 'ApacheIgnite' employees (distributed join): ", cache.query(qry).getAll());
qry.setArgs("Other");
print("Following people are 'Other' employees (distributed join): ", cache.query(qry).getAll());
}
/**
* Example for SQL queries to calculate average salary for a specific organization.
*/
private static void sqlQueryWithAggregation() {
IgniteCache<AffinityKey<Long>, Person> cache = Ignition.ignite().cache(COLLOCATED_PERSON_CACHE);
// Calculate average of salary of all persons in ApacheIgnite.
// Note that we also join on Organization cache as well.
String sql =
"select avg(salary) " +
"from Person, \"" + ORG_CACHE + "\".Organization as org " +
"where Person.orgId = org.id " +
"and lower(org.name) = lower(?)";
QueryCursor<List<?>> cursor = cache.query(new SqlFieldsQuery(sql).setArgs("ApacheIgnite"));
// Calculate average salary for a specific organization.
print("Average salary for 'ApacheIgnite' employees: ", cursor.getAll());
}
/**
* Example for SQL-based fields queries that return only required
* fields instead of whole key-value pairs.
*/
private static void sqlFieldsQuery() {
IgniteCache<Long, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
// Execute query to get names of all employees.
QueryCursor<List<?>> cursor = cache.query(new SqlFieldsQuery(
"select concat(firstName, ' ', lastName) from Person"));
// In this particular case each row will have one element with full name of an employees.
List<List<?>> res = cursor.getAll();
// Print names.
print("Names of all employees:", res);
}
/**
* Example for SQL-based fields queries that return only required
* fields instead of whole key-value pairs.
*/
private static void sqlFieldsQueryWithJoin() {
IgniteCache<AffinityKey<Long>, Person> cache = Ignition.ignite().cache(COLLOCATED_PERSON_CACHE);
// Execute query to get names of all employees.
String sql =
"select concat(firstName, ' ', lastName), org.name " +
"from Person, \"" + ORG_CACHE + "\".Organization as org " +
"where Person.orgId = org.id";
QueryCursor<List<?>> cursor = cache.query(new SqlFieldsQuery(sql));
// In this particular case each row will have one element with full name of an employees.
List<List<?>> res = cursor.getAll();
// Print persons' names and organizations' names.
print("Names of all employees and organizations they belong to: ", res);
}
/**
* Populate cache with test data.
*/
private static void initialize() {
IgniteCache<Long, Organization> orgCache = Ignition.ignite().cache(ORG_CACHE);
// Clear cache before running the example.
orgCache.clear();
// Organizations.
Organization org1 = new Organization("ApacheIgnite");
Organization org2 = new Organization("Other");
orgCache.put(org1.id(), org1);
orgCache.put(org2.id(), org2);
IgniteCache<AffinityKey<Long>, Person> colPersonCache = Ignition.ignite().cache(COLLOCATED_PERSON_CACHE);
IgniteCache<Long, Person> personCache = Ignition.ignite().cache(PERSON_CACHE);
// Clear caches before running the example.
colPersonCache.clear();
personCache.clear();
// People.
Person p1 = new Person(org1, "John", "Doe", 2000, "John Doe has Master Degree.");
Person p2 = new Person(org1, "Jane", "Doe", 1000, "Jane Doe has Bachelor Degree.");
Person p3 = new Person(org2, "John", "Smith", 1000, "John Smith has Bachelor Degree.");
Person p4 = new Person(org2, "Jane", "Smith", 2000, "Jane Smith has Master Degree.");
// Note that in this example we use custom affinity key for Person objects
// to ensure that all persons are collocated with their organizations.
colPersonCache.put(p1.key(), p1);
colPersonCache.put(p2.key(), p2);
colPersonCache.put(p3.key(), p3);
colPersonCache.put(p4.key(), p4);
// These Person objects are not collocated with their organizations.
personCache.put(p1.id, p1);
personCache.put(p2.id, p2);
personCache.put(p3.id, p3);
personCache.put(p4.id, p4);
}
/**
* Prints message and query results.
*
* @param msg Message to print before all objects are printed.
* @param col Query results.
*/
private static void print(String msg, Iterable<?> col) {
print(msg);
print(col);
}
/**
* Prints message.
*
* @param msg Message to print before all objects are printed.
*/
private static void print(String msg) {
System.out.println();
System.out.println(">>> " + msg);
}
/**
* Prints query results.
*
* @param col Query results.
*/
private static void print(Iterable<?> col) {
for (Object next : col)
System.out.println(">>> " + next);
}
}