cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject [1/3] cassandra git commit: Ensure correct filters with SASI clustering index
Date Thu, 24 Mar 2016 11:29:03 GMT
Repository: cassandra
Updated Branches:
  refs/heads/cassandra-3.5 f47d9769f -> 3fda52f24
  refs/heads/trunk 9b7d5734e -> 0a016ea1b


Ensure correct filters with SASI clustering index

Patch by Sam Tunnicliffe; reviewed by Jordan West for CASSANDRA-11397


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/3fda52f2
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/3fda52f2
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/3fda52f2

Branch: refs/heads/cassandra-3.5
Commit: 3fda52f247415c1eace35af80c74bc433a57254b
Parents: f47d976
Author: Sam Tunnicliffe <sam@beobal.com>
Authored: Tue Mar 22 10:53:35 2016 +0000
Committer: Sam Tunnicliffe <sam@beobal.com>
Committed: Thu Mar 24 11:22:40 2016 +0000

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../restrictions/PrimaryKeyRestrictionSet.java  | 17 +++++-
 .../restrictions/SingleColumnRestriction.java   |  8 +--
 .../restrictions/StatementRestrictions.java     |  2 +-
 .../unit/org/apache/cassandra/SchemaLoader.java | 42 +++++---------
 .../cassandra/index/sasi/SASIIndexTest.java     | 61 ++++++++++++--------
 6 files changed, 75 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/3fda52f2/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 85fca0f..7441abd 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.5
+ * Fix clustering and row filters for LIKE queries on clustering columns (CASSANDRA-11397)
 Merged from 3.0:
  * Allocate merkletrees with the correct size (CASSANDRA-11390)
  * Support streaming pre-3.0 sstables (CASSANDRA-10990)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3fda52f2/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
b/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
index 978ebbc..7d0c3df 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
@@ -55,6 +55,11 @@ final class PrimaryKeyRestrictionSet extends AbstractPrimaryKeyRestrictions
     private boolean in;
 
     /**
+     * <code>true</code> if the restrictions are corresponding to a LIKE, <code>false</code>
otherwise.
+     */
+    private boolean like;
+
+    /**
      * <code>true</code> if the restrictions are corresponding to a Slice, <code>false</code>
otherwise.
      */
     private boolean slice;
@@ -106,6 +111,8 @@ final class PrimaryKeyRestrictionSet extends AbstractPrimaryKeyRestrictions
             this.contains = true;
         else if (restriction.isIN() || primaryKeyRestrictions.isIN())
             this.in = true;
+        else if (restriction.isLIKE() || primaryKeyRestrictions.isLIKE())
+            this.like = true;
         else
             this.eq = true;
     }
@@ -138,6 +145,12 @@ final class PrimaryKeyRestrictionSet extends AbstractPrimaryKeyRestrictions
     }
 
     @Override
+    public boolean isLIKE()
+    {
+        return like;
+    }
+
+    @Override
     public boolean isContains()
     {
         return contains;
@@ -220,7 +233,7 @@ final class PrimaryKeyRestrictionSet extends AbstractPrimaryKeyRestrictions
         {
             ColumnDefinition def = r.getFirstColumn();
 
-            if (keyPosition != def.position() || r.isContains())
+            if (keyPosition != def.position() || r.isContains() || r.isLIKE())
                 break;
 
             if (r.isSlice())
@@ -296,7 +309,7 @@ final class PrimaryKeyRestrictionSet extends AbstractPrimaryKeyRestrictions
             ColumnDefinition columnDef = restriction.getFirstColumn();
 
             // We ignore all the clustering columns that can be handled by slices.
-            if (!isPartitionKey && !restriction.isContains()&& position ==
columnDef.position())
+            if (!isPartitionKey && !(restriction.isContains() || restriction.isLIKE())
&& position == columnDef.position())
             {
                 position = restriction.getLastColumn().position() + 1;
                 if (!restriction.hasSupportingIndex(indexManager))

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3fda52f2/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java
b/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java
index d237d02..ab4815a 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java
@@ -704,10 +704,10 @@ public abstract class SingleColumnRestriction extends AbstractRestriction
         @Override
         public MultiCBuilder appendTo(MultiCBuilder builder, QueryOptions options)
         {
-            // LIKE could be used with clustering columns as soon as they are indexed,
-            // but we have to hide such expression from clustering filter since it
-            // can only filter based on the complete values.
-            return builder;
+            // LIKE can be used with clustering columns, but as it doesn't
+            // represent an actual clustering value, it can't be used in a
+            // clustering filter.
+            throw new UnsupportedOperationException();
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3fda52f2/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
index 123e33b..0672a99 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
@@ -737,7 +737,7 @@ public final class StatementRestrictions
         // this would mean a 'SELECT *' on a static compact table would query whole partitions,
even though we'll only return
         // the static part as far as CQL is concerned. This is thus mostly an optimization
to use the query-by-name path).
         int numberOfClusteringColumns = cfm.isStaticCompactTable() ? 0 : cfm.clusteringColumns().size();
-        // it is a range query if it has at least one the column alias for which no relation
is defined or is not EQ.
+        // it is a range query if it has at least one the column alias for which no relation
is defined or is not EQ or IN.
         return clusteringColumnsRestrictions.size() < numberOfClusteringColumns
             || (!clusteringColumnsRestrictions.isEQ() && !clusteringColumnsRestrictions.isIN());
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3fda52f2/test/unit/org/apache/cassandra/SchemaLoader.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/SchemaLoader.java b/test/unit/org/apache/cassandra/SchemaLoader.java
index 9a8c424..e68dd94 100644
--- a/test/unit/org/apache/cassandra/SchemaLoader.java
+++ b/test/unit/org/apache/cassandra/SchemaLoader.java
@@ -578,6 +578,11 @@ public class SchemaLoader
 
     public static CFMetaData clusteringSASICFMD(String ksName, String cfName)
     {
+        return clusteringSASICFMD(ksName, cfName, "location", "age", "height", "score");
+    }
+
+    public static CFMetaData clusteringSASICFMD(String ksName, String cfName, String...indexedColumns)
+    {
         CFMetaData cfm = CFMetaData.Builder.create(ksName, cfName)
                                            .addPartitionKey("name", UTF8Type.instance)
                                            .addClusteringColumn("location", UTF8Type.instance)
@@ -586,32 +591,17 @@ public class SchemaLoader
                                            .addRegularColumn("score", DoubleType.instance)
                                            .build();
 
-        cfm.indexes(cfm.getIndexes()
-                       .with(IndexMetadata.fromSchemaMetadata("location", IndexMetadata.Kind.CUSTOM,
new HashMap<String, String>()
-                       {{
-                           put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName());
-                           put(IndexTarget.TARGET_OPTION_NAME, "location");
-                           put("mode", OnDiskIndexBuilder.Mode.PREFIX.toString());
-                       }}))
-                       .with(IndexMetadata.fromSchemaMetadata("age", IndexMetadata.Kind.CUSTOM,
new HashMap<String, String>()
-                       {{
-                           put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName());
-                           put(IndexTarget.TARGET_OPTION_NAME, "age");
-                           put("mode", OnDiskIndexBuilder.Mode.PREFIX.toString());
-                       }}))
-                       .with(IndexMetadata.fromSchemaMetadata("height", IndexMetadata.Kind.CUSTOM,
new HashMap<String, String>()
-                       {{
-                           put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName());
-                           put(IndexTarget.TARGET_OPTION_NAME, "height");
-                           put("mode", OnDiskIndexBuilder.Mode.PREFIX.toString());
-                       }}))
-                       .with(IndexMetadata.fromSchemaMetadata("score", IndexMetadata.Kind.CUSTOM,
new HashMap<String, String>()
-                       {{
-                           put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName());
-                           put(IndexTarget.TARGET_OPTION_NAME, "score");
-                           put("mode", OnDiskIndexBuilder.Mode.PREFIX.toString());
-                       }})));
-
+        Indexes indexes = cfm.getIndexes();
+        for (String indexedColumn : indexedColumns)
+        {
+            indexes = indexes.with(IndexMetadata.fromSchemaMetadata(indexedColumn, IndexMetadata.Kind.CUSTOM,
new HashMap<String, String>()
+            {{
+                put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName());
+                put(IndexTarget.TARGET_OPTION_NAME, indexedColumn);
+                put("mode", OnDiskIndexBuilder.Mode.PREFIX.toString());
+            }}));
+        }
+        cfm.indexes(indexes);
         return cfm;
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3fda52f2/test/unit/org/apache/cassandra/index/sasi/SASIIndexTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/index/sasi/SASIIndexTest.java b/test/unit/org/apache/cassandra/index/sasi/SASIIndexTest.java
index c9d66f7..ca6e9a1 100644
--- a/test/unit/org/apache/cassandra/index/sasi/SASIIndexTest.java
+++ b/test/unit/org/apache/cassandra/index/sasi/SASIIndexTest.java
@@ -80,7 +80,8 @@ public class SASIIndexTest
 
     private static final String KS_NAME = "sasi";
     private static final String CF_NAME = "test_cf";
-    private static final String CLUSTERING_CF_NAME = "clustering_test_cf";
+    private static final String CLUSTERING_CF_NAME_1 = "clustering_test_cf_1";
+    private static final String CLUSTERING_CF_NAME_2 = "clustering_test_cf_2";
 
     @BeforeClass
     public static void loadSchema() throws ConfigurationException
@@ -90,7 +91,8 @@ public class SASIIndexTest
         MigrationManager.announceNewKeyspace(KeyspaceMetadata.create(KS_NAME,
                                                                      KeyspaceParams.simpleTransient(1),
                                                                      Tables.of(SchemaLoader.sasiCFMD(KS_NAME,
CF_NAME),
-                                                                               SchemaLoader.clusteringSASICFMD(KS_NAME,
CLUSTERING_CF_NAME))));
+                                                                               SchemaLoader.clusteringSASICFMD(KS_NAME,
CLUSTERING_CF_NAME_1),
+                                                                               SchemaLoader.clusteringSASICFMD(KS_NAME,
CLUSTERING_CF_NAME_2, "location"))));
     }
 
     @After
@@ -1621,64 +1623,64 @@ public class SASIIndexTest
 
     public void testClusteringIndexes(boolean forceFlush) throws Exception
     {
-        ColumnFamilyStore store = Keyspace.open(KS_NAME).getColumnFamilyStore(CLUSTERING_CF_NAME);
+        ColumnFamilyStore store = Keyspace.open(KS_NAME).getColumnFamilyStore(CLUSTERING_CF_NAME_1);
 
-        executeCQL("INSERT INTO %s.%s (name, location, age, height, score) VALUES (?, ?,
?, ?, ?)", "Pavel", "US", 27, 183, 1.0);
-        executeCQL("INSERT INTO %s.%s (name, location, age, height, score) VALUES (?, ?,
?, ?, ?)", "Pavel", "BY", 28, 182, 2.0);
-        executeCQL("INSERT INTO %s.%s (name, location, age, height, score) VALUES (?, ?,
?, ?, ?)", "Jordan", "US", 27, 182, 1.0);
+        executeCQL(CLUSTERING_CF_NAME_1, "INSERT INTO %s.%s (name, location, age, height,
score) VALUES (?, ?, ?, ?, ?)", "Pavel", "US", 27, 183, 1.0);
+        executeCQL(CLUSTERING_CF_NAME_1, "INSERT INTO %s.%s (name, location, age, height,
score) VALUES (?, ?, ?, ?, ?)", "Pavel", "BY", 28, 182, 2.0);
+        executeCQL(CLUSTERING_CF_NAME_1 ,"INSERT INTO %s.%s (name, location, age, height,
score) VALUES (?, ?, ?, ?, ?)", "Jordan", "US", 27, 182, 1.0);
 
         if (forceFlush)
             store.forceBlockingFlush();
 
         UntypedResultSet results;
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE location = ? ALLOW FILTERING", "US");
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE location =
? ALLOW FILTERING", "US");
         Assert.assertNotNull(results);
         Assert.assertEquals(2, results.size());
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE age >= ? AND height = ? ALLOW
FILTERING", 27, 182);
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE age >= ?
AND height = ? ALLOW FILTERING", 27, 182);
         Assert.assertNotNull(results);
         Assert.assertEquals(2, results.size());
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE age = ? AND height = ? ALLOW FILTERING",
28, 182);
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE age = ? AND
height = ? ALLOW FILTERING", 28, 182);
         Assert.assertNotNull(results);
         Assert.assertEquals(1, results.size());
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE age >= ? AND height = ? AND score
>= ? ALLOW FILTERING", 27, 182, 1.0);
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE age >= ?
AND height = ? AND score >= ? ALLOW FILTERING", 27, 182, 1.0);
         Assert.assertNotNull(results);
         Assert.assertEquals(2, results.size());
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE age >= ? AND height = ? AND score
= ? ALLOW FILTERING", 27, 182, 1.0);
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE age >= ?
AND height = ? AND score = ? ALLOW FILTERING", 27, 182, 1.0);
         Assert.assertNotNull(results);
         Assert.assertEquals(1, results.size());
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE location = ? AND age >= ? ALLOW
FILTERING", "US", 27);
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE location =
? AND age >= ? ALLOW FILTERING", "US", 27);
         Assert.assertNotNull(results);
         Assert.assertEquals(2, results.size());
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE location = ? ALLOW FILTERING", "BY");
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE location =
? ALLOW FILTERING", "BY");
         Assert.assertNotNull(results);
         Assert.assertEquals(1, results.size());
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE location LIKE 'U%%' ALLOW FILTERING");
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE location LIKE
'U%%' ALLOW FILTERING");
         Assert.assertNotNull(results);
         Assert.assertEquals(2, results.size());
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE location LIKE 'U%%' AND height >=
183 ALLOW FILTERING");
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE location LIKE
'U%%' AND height >= 183 ALLOW FILTERING");
         Assert.assertNotNull(results);
         Assert.assertEquals(1, results.size());
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE location LIKE 'US%%' ALLOW FILTERING");
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE location LIKE
'US%%' ALLOW FILTERING");
         Assert.assertNotNull(results);
         Assert.assertEquals(2, results.size());
 
-        results = executeCQL("SELECT * FROM %s.%s WHERE location LIKE 'US' ALLOW FILTERING");
+        results = executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE location LIKE
'US' ALLOW FILTERING");
         Assert.assertNotNull(results);
         Assert.assertEquals(2, results.size());
 
         try
         {
-            executeCQL("SELECT * FROM %s.%s WHERE location LIKE '%%U' ALLOW FILTERING");
+            executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE location LIKE '%%U'
ALLOW FILTERING");
             Assert.fail();
         }
         catch (InvalidRequestException e)
@@ -1689,7 +1691,7 @@ public class SASIIndexTest
 
         try
         {
-            executeCQL("SELECT * FROM %s.%s WHERE location LIKE '%%' ALLOW FILTERING");
+            executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE location LIKE '%%'
ALLOW FILTERING");
             Assert.fail();
         }
         catch (SyntaxException e)
@@ -1700,7 +1702,7 @@ public class SASIIndexTest
 
         try
         {
-            executeCQL("SELECT * FROM %s.%s WHERE location LIKE '%%%%' ALLOW FILTERING");
+            executeCQL(CLUSTERING_CF_NAME_1 ,"SELECT * FROM %s.%s WHERE location LIKE '%%%%'
ALLOW FILTERING");
             Assert.fail();
         }
         catch (SyntaxException e)
@@ -1708,6 +1710,19 @@ public class SASIIndexTest
             Assert.assertTrue(e.getMessage().contains("empty"));
             // expected
         }
+
+        // check restrictions on non-indexed clustering columns when preceding columns are
indexed
+        store = Keyspace.open(KS_NAME).getColumnFamilyStore(CLUSTERING_CF_NAME_2);
+        executeCQL(CLUSTERING_CF_NAME_2 ,"INSERT INTO %s.%s (name, location, age, height,
score) VALUES (?, ?, ?, ?, ?)", "Tony", "US", 43, 184, 2.0);
+        executeCQL(CLUSTERING_CF_NAME_2 ,"INSERT INTO %s.%s (name, location, age, height,
score) VALUES (?, ?, ?, ?, ?)", "Christopher", "US", 27, 180, 1.0);
+
+        if (forceFlush)
+            store.forceBlockingFlush();
+
+        results = executeCQL(CLUSTERING_CF_NAME_2 ,"SELECT * FROM %s.%s WHERE location LIKE
'US' AND age = 43 ALLOW FILTERING");
+        Assert.assertNotNull(results);
+        Assert.assertEquals(1, results.size());
+        Assert.assertEquals("Tony", results.one().getString("name"));
     }
 
     @Test
@@ -2037,7 +2052,7 @@ public class SASIIndexTest
     {
         Keyspace ks = Keyspace.open(KS_NAME);
         ks.getColumnFamilyStore(CF_NAME).truncateBlocking();
-        ks.getColumnFamilyStore(CLUSTERING_CF_NAME).truncateBlocking();
+        ks.getColumnFamilyStore(CLUSTERING_CF_NAME_1).truncateBlocking();
     }
 
     private static Set<String> getIndexed(ColumnFamilyStore store, int maxResults,
Expression... expressions)
@@ -2150,9 +2165,9 @@ public class SASIIndexTest
         }};
     }
 
-    private UntypedResultSet executeCQL(String query, Object... values)
+    private UntypedResultSet executeCQL(String cfName, String query, Object... values)
     {
-        return QueryProcessor.executeOnceInternal(String.format(query, KS_NAME, CLUSTERING_CF_NAME),
values);
+        return QueryProcessor.executeOnceInternal(String.format(query, KS_NAME, cfName),
values);
     }
 
     private Set<String> executeCQLWithKeys(String rawStatement) throws Exception


Mime
View raw message