Cassandra
  1. Cassandra
  2. CASSANDRA-4511

Secondary index support for CQL3 collections

    Details

    • Type: Improvement Improvement
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Fix Version/s: 2.1 beta1
    • Component/s: None
    • Labels:
      None

      Description

      We should allow to 2ndary index on collections. A typical use case would be to add a 'tag set<String>' to say a user profile and to query users based on what tag they have.

      1. 4511.txt
        43 kB
        Sylvain Lebresne

        Issue Links

          Activity

          Hide
          Sylvain Lebresne added a comment -

          I'll note that support for lists should be fairly simple following CASSANDRA-3680. I haven't tried yet but it might well even be that it works out of the box. It would be the same for indexing based on map values.

          However, indexing based on set values (or on map keys, but I don't know if we want that) is more complicated, because we need to index one of the component of the composite name, so it probably require a new Searcher.

          Show
          Sylvain Lebresne added a comment - I'll note that support for lists should be fairly simple following CASSANDRA-3680 . I haven't tried yet but it might well even be that it works out of the box. It would be the same for indexing based on map values. However, indexing based on set values (or on map keys, but I don't know if we want that) is more complicated, because we need to index one of the component of the composite name, so it probably require a new Searcher.
          Hide
          Jonathan Ellis added a comment -

          Kind of think we should push this to 2.1. There's a lot of other things I'd rather have in 2.0...

          Show
          Jonathan Ellis added a comment - Kind of think we should push this to 2.1. There's a lot of other things I'd rather have in 2.0...
          Hide
          Sylvain Lebresne added a comment -

          Attaching patch that allows to create index on collections (with the usual syntax) and allow to query them using CONTAINS, so

          SELECT * FROM myTable WHERE tags CONTAINS 'awesome';
          

          What is indexed is the collection values. For lists and sets there is nothing else to index, but for maps, this means we index the map values and it could make sense to index the map keys. Technically, this isn't adding much difficulty since indexing map keys is similar to indexed set values. On the query side, we could just support

          SELECT * FROM myTable WHERE myMap CONTAINS KEY 'foo';
          

          and in fact the attached patch contains 80% of what's needed to support this. But it's not yet supported because of 2 reasons:

          1. I realized mid-implementation that if we wanted to support indexing map keys, this means we might need to support indexing both keys and values of the same map, which internally require to support multiple SecondaryIndex object on the same ColumnDefinition and we'd need a bit of refactor of the 2ndary index API to make that work properly.
          2. it's more of a detail but I was not entirely sure what the best syntax to create indexes could be. I supposed we could have something like
            CREATE INDEX ON KEY test(myMap)
            

            but I'm not entirely fan for some reason.

          Anyway, I've left most parts of the support for this CONTAINS KEY in the patch (but the syntax is not allowed). If we decide indexing map keys is something we just don't want, then I'm fine pulling them out of the patch. Otherwise, I'd rather left them (it doesn't add much to the review of the current patch honestly) but finish full support in a followup ticket.

          I've pushed a dtests for this.

          Show
          Sylvain Lebresne added a comment - Attaching patch that allows to create index on collections (with the usual syntax) and allow to query them using CONTAINS , so SELECT * FROM myTable WHERE tags CONTAINS 'awesome'; What is indexed is the collection values. For lists and sets there is nothing else to index, but for maps, this means we index the map values and it could make sense to index the map keys. Technically, this isn't adding much difficulty since indexing map keys is similar to indexed set values. On the query side, we could just support SELECT * FROM myTable WHERE myMap CONTAINS KEY 'foo'; and in fact the attached patch contains 80% of what's needed to support this. But it's not yet supported because of 2 reasons: I realized mid-implementation that if we wanted to support indexing map keys, this means we might need to support indexing both keys and values of the same map, which internally require to support multiple SecondaryIndex object on the same ColumnDefinition and we'd need a bit of refactor of the 2ndary index API to make that work properly. it's more of a detail but I was not entirely sure what the best syntax to create indexes could be. I supposed we could have something like CREATE INDEX ON KEY test(myMap) but I'm not entirely fan for some reason. Anyway, I've left most parts of the support for this CONTAINS KEY in the patch (but the syntax is not allowed). If we decide indexing map keys is something we just don't want, then I'm fine pulling them out of the patch. Otherwise, I'd rather left them (it doesn't add much to the review of the current patch honestly) but finish full support in a followup ticket. I've pushed a dtests for this.
          Hide
          Jonathan Ellis added a comment -

          I'm struggling to think of a use case for indexing map keys. /cc Patrick McFadin Tupshin Harper

          Also, it occurs to me that we don't need to add new syntax if we did this instead:

          SELECT * FROM myTable WHERE 'awesome' IN tags;
          
          Show
          Jonathan Ellis added a comment - I'm struggling to think of a use case for indexing map keys. /cc Patrick McFadin Tupshin Harper Also, it occurs to me that we don't need to add new syntax if we did this instead: SELECT * FROM myTable WHERE 'awesome' IN tags;
          Hide
          Sylvain Lebresne added a comment -

          I'm struggling to think of a use case for indexing map keys

          One thing that comes into mind is tags, but where you want to attach some data to it. Say, when was the tag added, or maybe whom added it. In that case, you could imagine wanting to index both the keys (the tag itself, to know what object has tag X) and the values (for instance to know 'which object did user Y tagged').

          And btw, technically there is not a whole lot of difficulty adding this, we just need to go a bit over the 2ndary index API to make sure we can add more than one index on a given name. But that API probably need some cleanup anyway.

          Also, it occurs to me that we don't need to add new syntax

          True. But I'll note that 1) we don't, technically speaking, support this syntax currently, we only support 'IN ?' and 'IN (...)', so it save adding one token to the lexer but doesn't entirely save from updating the grammar and 2) internally, I still think we'd want to keep it a separate case from other IN because it has different rules anyway. Overall, I don't mind using IN over CONTAINS if we think that's a better syntax but I don't think one of the arguments should be "because it makes things easier internally" (didn't meant to imply this was your argument btw, just making sure we agree on why we would make the choice) because I don't think that's true.

          In any case, as far as I'm concerned, I don't care a whole lot between CONTAINS and IN, expect maybe that it feels easier to extend the syntax to map keys with CONTAINS (using CONTAINS KEY).

          Show
          Sylvain Lebresne added a comment - I'm struggling to think of a use case for indexing map keys One thing that comes into mind is tags, but where you want to attach some data to it. Say, when was the tag added, or maybe whom added it. In that case, you could imagine wanting to index both the keys (the tag itself, to know what object has tag X) and the values (for instance to know 'which object did user Y tagged'). And btw, technically there is not a whole lot of difficulty adding this, we just need to go a bit over the 2ndary index API to make sure we can add more than one index on a given name. But that API probably need some cleanup anyway. Also, it occurs to me that we don't need to add new syntax True. But I'll note that 1) we don't, technically speaking, support this syntax currently, we only support 'IN ?' and 'IN (...)', so it save adding one token to the lexer but doesn't entirely save from updating the grammar and 2) internally, I still think we'd want to keep it a separate case from other IN because it has different rules anyway. Overall, I don't mind using IN over CONTAINS if we think that's a better syntax but I don't think one of the arguments should be "because it makes things easier internally" (didn't meant to imply this was your argument btw, just making sure we agree on why we would make the choice) because I don't think that's true. In any case, as far as I'm concerned, I don't care a whole lot between CONTAINS and IN, expect maybe that it feels easier to extend the syntax to map keys with CONTAINS (using CONTAINS KEY).
          Hide
          Jonathan Ellis added a comment -

          How could this extend to user types?

          Show
          Jonathan Ellis added a comment - How could this extend to user types?
          Hide
          Zachary Marcantel added a comment - - edited

          I can think of (and need this for) a few use cases. They do revolve around more of a filtering aspect, however.

          It can be said that sometimes models/data/rows belong to a "theoretical list" that contain infinite possibilities.

          Naturally, you do not want to store all possibilities, but may want to filter on those which are true while ignoring all other possiblities.

          Examples of these lists could be:

          • Things of interest to a user
            • LinkedIn calls these skills, Facebook has 'liked pages', etc
          • Movies Watched
            • Netflix surely doesn't (want to) have a USER x MOVIES sized table
            • Nor do they want (user x movies) number of columnfamilies
          • Places Visited
            • set yes/no for EVERY location on Earth?

          Benchmarks may prove me wrong, but theoretically the performance hit would be minimal if the data is truly partitioned well, collections are kept small, and secondary indexing used only as a filter and not data storage.

          Dynamic columns may make some of my examples easier, but bring their own headaches (post-filling dynamically created columns, massively wide tables, largely unused data == disk bloat).

          I'll give a couple examples and use Jonathan Ellis syntax, as well as a potential map-based indexing.

          • Users contained in group(s):
            • Note: this could be done with columns, but if we assume groups can contain infinitely many possibilities (like Facebook groups), this becomes an issue)
          • SELECT * FROM main.users WHERE 'players' IN groups AND 'admins' NOT IN groups;
            
          • Filter on toggle-based UI elements within user profiles:
            SELECT * FROM main.users WHERE notify['email'] = true;
            

          Currently, one would have to detail the entirety of the list that has been seen in one of three ways:

          CREATE TABLE main.interests (
              interest_name TEXT PRIMARY KEY,
              users LIST <TEXT>
          );
          

          OR

          CREATE TABLE main.users (
              id UUID PRIMARY KEY,
              ... other user fields ...
              interests LIST <TEXT>
          );
          

          OR

          CREATE TABLE main.users (
              id UUID PRIMARY KEY,
              a BOOLEAN,
              b BOOLEAN,
              ... Iterate through possibilities ...
              z BOOLEAN
          );
          

          The first two would require post-result processing (map-reduce or similar) to find just the users containing a certain key/value. The last example would require much wasted disk space and post-filling of dynamically created columns.

          Rather, with indexing:

          CREATE TABLE main.users (
              id UUID PRIMARY KEY,
              name TEXT,
              age INT,
              interests LIST <TEXT>
          );
          

          where 'interests' is a relatively small (~10-25 elements) list that can be filtered by:

          SELECT * FROM main.users WHERE 'baseball' IN interests AND 'soccer' IN interests;
          
          Show
          Zachary Marcantel added a comment - - edited I can think of (and need this for) a few use cases. They do revolve around more of a filtering aspect, however. It can be said that sometimes models/data/rows belong to a "theoretical list" that contain infinite possibilities. Naturally, you do not want to store all possibilities, but may want to filter on those which are true while ignoring all other possiblities. Examples of these lists could be: Things of interest to a user LinkedIn calls these skills, Facebook has 'liked pages', etc Movies Watched Netflix surely doesn't (want to) have a USER x MOVIES sized table Nor do they want (user x movies) number of columnfamilies Places Visited set yes/no for EVERY location on Earth? Benchmarks may prove me wrong, but theoretically the performance hit would be minimal if the data is truly partitioned well, collections are kept small, and secondary indexing used only as a filter and not data storage. Dynamic columns may make some of my examples easier, but bring their own headaches (post-filling dynamically created columns, massively wide tables, largely unused data == disk bloat). I'll give a couple examples and use Jonathan Ellis syntax, as well as a potential map-based indexing. Users contained in group(s): Note: this could be done with columns, but if we assume groups can contain infinitely many possibilities (like Facebook groups), this becomes an issue) SELECT * FROM main.users WHERE 'players' IN groups AND 'admins' NOT IN groups; Filter on toggle-based UI elements within user profiles: SELECT * FROM main.users WHERE notify['email'] = true; Currently, one would have to detail the entirety of the list that has been seen in one of three ways: CREATE TABLE main.interests ( interest_name TEXT PRIMARY KEY, users LIST <TEXT> ); OR CREATE TABLE main.users ( id UUID PRIMARY KEY, ... other user fields ... interests LIST <TEXT> ); OR CREATE TABLE main.users ( id UUID PRIMARY KEY, a BOOLEAN, b BOOLEAN, ... Iterate through possibilities ... z BOOLEAN ); The first two would require post-result processing (map-reduce or similar) to find just the users containing a certain key/value. The last example would require much wasted disk space and post-filling of dynamically created columns. Rather, with indexing: CREATE TABLE main.users ( id UUID PRIMARY KEY, name TEXT, age INT, interests LIST <TEXT> ); where 'interests' is a relatively small (~10-25 elements) list that can be filtered by: SELECT * FROM main.users WHERE 'baseball' IN interests AND 'soccer' IN interests;
          Hide
          Jeremiah Jordan added a comment -

          I definitely think being able to index the key of a map is useful. There are many times it would have been nice for me to be able to query "what rows have this dynamic column", I actually built my own 2i's so I could do that... Since maps are basically one of the big replacements for dynamic columns, I think it would be very useful to index the keys.

          Show
          Jeremiah Jordan added a comment - I definitely think being able to index the key of a map is useful. There are many times it would have been nice for me to be able to query "what rows have this dynamic column", I actually built my own 2i's so I could do that... Since maps are basically one of the big replacements for dynamic columns, I think it would be very useful to index the keys.
          Hide
          Alex Cruise added a comment -

          FWIW I had a strong use case for indexing both map keys and values. The indexing difficulties (not just in collections) are a big part of the reason I ended up going back to postgres, at least temporarily.

          My data is tagged with customer-supplied arbitrary name/values, and I need to be able to search on both quickly.

          Show
          Alex Cruise added a comment - FWIW I had a strong use case for indexing both map keys and values. The indexing difficulties (not just in collections) are a big part of the reason I ended up going back to postgres, at least temporarily. My data is tagged with customer-supplied arbitrary name/values, and I need to be able to search on both quickly.
          Hide
          Sylvain Lebresne added a comment -

          How could this extend to user types?

          Technically, we'd need versions of the existing CompositesIndex (the one on "regular" columns and the 2 new ones introduced by this patch for user types within collections) that knows how to reach into the value to find the actual value indexed. But that should be fairly straightforward.

          Syntax-wise, that's a harder problem . For user types not in a collection, the simplest solution seems to just use the dot notation (so SELECT * FROM bar WHERE x.y = 'foo') but I suppose your meant user types in collections, i.e, given

          CREATE USER TYPE sometype (y text, z text)
          CREATE TABLE bar (k int PRIMARY KEY, x set<sometype>)
          

          how do you index the 'y' field of the values in 'x'. In which case I don't really have a good syntax to offer so far, not even to declare the index in the first place. Maybe we'd have to resort to some sort of variable binding, something like

          SELECT * FROM bar WHERE $e.y = 'foo' FOR $e IN x
          

          (where I use a '$' to make it clear that '$e' would just be some form of query-local variable but we can do without it)

          Since maps are basically one of the big replacements for dynamic columns

          Oh My...

          Show
          Sylvain Lebresne added a comment - How could this extend to user types? Technically, we'd need versions of the existing CompositesIndex (the one on "regular" columns and the 2 new ones introduced by this patch for user types within collections) that knows how to reach into the value to find the actual value indexed. But that should be fairly straightforward. Syntax-wise, that's a harder problem . For user types not in a collection, the simplest solution seems to just use the dot notation (so SELECT * FROM bar WHERE x.y = 'foo') but I suppose your meant user types in collections, i.e, given CREATE USER TYPE sometype (y text, z text) CREATE TABLE bar (k int PRIMARY KEY, x set<sometype>) how do you index the 'y' field of the values in 'x'. In which case I don't really have a good syntax to offer so far, not even to declare the index in the first place. Maybe we'd have to resort to some sort of variable binding, something like SELECT * FROM bar WHERE $e.y = 'foo' FOR $e IN x (where I use a '$' to make it clear that '$e' would just be some form of query-local variable but we can do without it) Since maps are basically one of the big replacements for dynamic columns Oh My...
          Hide
          Jonathan Ellis added a comment -

          how do you index the 'y' field of the values in 'x'

          Yeah, that's where I was going.

          I note that mongodb only allows indexing top-level fields: http://docs.mongodb.org/manual/core/index-single/ http://docs.mongodb.org/manual/core/index-multikey/

          Created CASSANDRA-6382 for indexing user types with dot notation. Let's skip the collections complication.

          (Does sound like we have a consensus for indexing map keys.)

          Show
          Jonathan Ellis added a comment - how do you index the 'y' field of the values in 'x' Yeah, that's where I was going. I note that mongodb only allows indexing top-level fields: http://docs.mongodb.org/manual/core/index-single/ http://docs.mongodb.org/manual/core/index-multikey/ Created CASSANDRA-6382 for indexing user types with dot notation. Let's skip the collections complication. (Does sound like we have a consensus for indexing map keys.)
          Hide
          Sylvain Lebresne added a comment -

          Does sound like we have a consensus for indexing map keys.

          Yep, but as said above, I'd rather tackle the remaining bits of that in CASSANDRA-6383 since there a few added difficulties related to the 2ndary index API.

          We do need to decide though, do we stick to CONTAINS here (and use CONTAINS KEY in CASSANDRA-6383) or do we prefer IN (and we need a new idea for CASSANDRA-6383). I personally have a slight preference for CONTAINS just because the extension to map keys seems more straightforward, but I don't care a whole lot otherwise.

          Show
          Sylvain Lebresne added a comment - Does sound like we have a consensus for indexing map keys. Yep, but as said above, I'd rather tackle the remaining bits of that in CASSANDRA-6383 since there a few added difficulties related to the 2ndary index API. We do need to decide though, do we stick to CONTAINS here (and use CONTAINS KEY in CASSANDRA-6383 ) or do we prefer IN (and we need a new idea for CASSANDRA-6383 ). I personally have a slight preference for CONTAINS just because the extension to map keys seems more straightforward, but I don't care a whole lot otherwise.
          Hide
          Jonathan Ellis added a comment -

          CONTAINS WFM.

          Show
          Jonathan Ellis added a comment - CONTAINS WFM.
          Hide
          Aleksey Yeschenko added a comment -

          CONTAINS WFM as well. Sylvain Lebresne If the patch is reviewable in the current form, and doesn't need any modifications post all the discussion, can you please switch the issue to Patch Available (with a rebased patch if necessary)?
          Thanks.

          Show
          Aleksey Yeschenko added a comment - CONTAINS WFM as well. Sylvain Lebresne If the patch is reviewable in the current form, and doesn't need any modifications post all the discussion, can you please switch the issue to Patch Available (with a rebased patch if necessary)? Thanks.
          Hide
          Sylvain Lebresne added a comment -

          Rebased just in case. The patch is ready but what I said above stands: it has a few minor bits pertaining to CONTAINS KEY. Since we agreed we wanted CONTAINS KEY anyway and since I don't think those bits makes review much harder, I'd rather left them here than going through the pain of extracting them into a separate patch.

          Show
          Sylvain Lebresne added a comment - Rebased just in case. The patch is ready but what I said above stands: it has a few minor bits pertaining to CONTAINS KEY. Since we agreed we wanted CONTAINS KEY anyway and since I don't think those bits makes review much harder, I'd rather left them here than going through the pain of extracting them into a separate patch.
          Hide
          Aleksey Yeschenko added a comment -

          LGTM

          nit: ExtendedFilter.findValueInCollection() is unused

          Show
          Aleksey Yeschenko added a comment - LGTM nit: ExtendedFilter.findValueInCollection() is unused
          Hide
          Sylvain Lebresne added a comment -

          Committed, thanks. CONTAINS KEY and extension to user types will be left to the followup tickets.

          Show
          Sylvain Lebresne added a comment - Committed, thanks. CONTAINS KEY and extension to user types will be left to the followup tickets.
          Hide
          Russ Hatch added a comment -

          I'm running into a bit of trouble testing here. When indexing a list column, and providing a list literal at insert, I get no results back when querying using contains. If create the row without the list, then do an update to add the list, the query returns the expected result.

          basic steps to reproduce:

          I'm working with a single node. I tried the test below with a list<text> and list<uuid> types and get the same behavior.
          
          Connected to test_cluster at 127.0.0.1:9160.
          [cqlsh 4.1.1 | Cassandra 2.1-SNAPSHOT | CQL spec 3.1.1 | Thrift protocol 19.39.0]
          Use HELP for help.
          cqlsh> create keyspace list_index_search with replication = {'class':'SimpleStrategy', 'replication_factor':1} ;
          cqlsh> CREATE TABLE list_index_search.users (
             ... user_id uuid PRIMARY KEY,
             ... email text,
             ... tags list<text>
             ... );
          cqlsh> CREATE INDEX user_uuids on list_index_search.users (tags);
          cqlsh> INSERT INTO list_index_search.users (user_id, email, tags)
             ... values (370e0d97-9c23-4718-9f74-ac5778bd8636, 'test@example.com', ['awesome']);
          cqlsh> select * from list_index_search.users where tags contains 'awesome';
          -- aaaaaaaaaargh, no rows!
          (0 rows)
          
          cqlsh> UPDATE list_index_search.users SET tags = ['awesome'] where user_id = 370e0d97-9c23-4718-9f74-ac5778bd8636;
          cqlsh> select * from list_index_search.users where tags contains 'awesome';
          
           user_id                              | email            | tags
          --------------------------------------+------------------+-------------
           370e0d97-9c23-4718-9f74-ac5778bd8636 | test@example.com | ['awesome']
          
          (1 rows)
          
          cqlsh> 
          
          Show
          Russ Hatch added a comment - I'm running into a bit of trouble testing here. When indexing a list column, and providing a list literal at insert, I get no results back when querying using contains. If create the row without the list, then do an update to add the list, the query returns the expected result. basic steps to reproduce: I'm working with a single node. I tried the test below with a list<text> and list<uuid> types and get the same behavior. Connected to test_cluster at 127.0.0.1:9160. [cqlsh 4.1.1 | Cassandra 2.1-SNAPSHOT | CQL spec 3.1.1 | Thrift protocol 19.39.0] Use HELP for help. cqlsh> create keyspace list_index_search with replication = {'class':'SimpleStrategy', 'replication_factor':1} ; cqlsh> CREATE TABLE list_index_search.users ( ... user_id uuid PRIMARY KEY, ... email text, ... tags list<text> ... ); cqlsh> CREATE INDEX user_uuids on list_index_search.users (tags); cqlsh> INSERT INTO list_index_search.users (user_id, email, tags) ... values (370e0d97-9c23-4718-9f74-ac5778bd8636, 'test@example.com', ['awesome']); cqlsh> select * from list_index_search.users where tags contains 'awesome'; -- aaaaaaaaaargh, no rows! (0 rows) cqlsh> UPDATE list_index_search.users SET tags = ['awesome'] where user_id = 370e0d97-9c23-4718-9f74-ac5778bd8636; cqlsh> select * from list_index_search.users where tags contains 'awesome'; user_id | email | tags --------------------------------------+------------------+------------- 370e0d97-9c23-4718-9f74-ac5778bd8636 | test@example.com | ['awesome'] (1 rows) cqlsh>
          Hide
          Naresh Yadav added a comment - - edited

          @Russ Hatch i also taken source code today and I am also facing exactly same issue..insert,select not working but insert,update tags,select works (not always but worked few times)..Step to reproduce http://pastebin.com/rxUhHab7 Please share if you have fix for this..

          Show
          Naresh Yadav added a comment - - edited @Russ Hatch i also taken source code today and I am also facing exactly same issue..insert,select not working but insert,update tags,select works (not always but worked few times)..Step to reproduce http://pastebin.com/rxUhHab7 Please share if you have fix for this..
          Hide
          Sylvain Lebresne added a comment -

          Alright, thanks for the testing Russ. I'll look what's going on but let's reopen in the meantime so I don't forget

          Show
          Sylvain Lebresne added a comment - Alright, thanks for the testing Russ. I'll look what's going on but let's reopen in the meantime so I don't forget
          Hide
          Sylvain Lebresne added a comment -

          This is a regression from CASSANDRA-6271, going to follow up there but it's not particularly specific to collection indexing so re-closing this.

          Show
          Sylvain Lebresne added a comment - This is a regression from CASSANDRA-6271 , going to follow up there but it's not particularly specific to collection indexing so re-closing this.
          Hide
          Lex Lythius added a comment -

          Note that CQL for Cassandra 2.x documentation (page 48) still says:

          Currently, you cannot create an index on a column of type map, set, or list.

          whereas CREATE INDEX syntax is accurate:

          CREATE CUSTOM INDEX IF NOT EXISTS index_name
          ON keyspace_name.table_name ( KEYS ( column_name ) )
          (USING class_name) (WITH OPTIONS = map)
          
          Show
          Lex Lythius added a comment - Note that CQL for Cassandra 2.x documentation (page 48) still says: Currently, you cannot create an index on a column of type map, set, or list. whereas CREATE INDEX syntax is accurate: CREATE CUSTOM INDEX IF NOT EXISTS index_name ON keyspace_name.table_name ( KEYS ( column_name ) ) (USING class_name) (WITH OPTIONS = map)
          Show
          K. B. Hahn added a comment - Thanks, Lex Lythius . http://www.datastax.com/documentation/cql/3.1/cql/cql_reference/collection_type_r.html

            People

            • Assignee:
              Sylvain Lebresne
              Reporter:
              Sylvain Lebresne
              Reviewer:
              Aleksey Yeschenko
            • Votes:
              6 Vote for this issue
              Watchers:
              20 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development