The syntax suggested by Ondrej is not working in some case in 2.0.11 and logged an issue for the same.
https://issues.apache.org/jira/browse/CASSANDRA-8797 Thanks Ajay On Feb 12, 2015 11:01 PM, "Bulat Shakirzyanov" < bulat.shakirzya...@datastax.com> wrote: > Fixed my Mail.app settings so you can see my actual name, sorry. > > On Feb 12, 2015, at 8:55 AM, DataStax <bulat.shakirzya...@datastax.com> > wrote: > > Hello, > > As was mentioned earlier, the Java driver doesn’t actually perform > pagination. > > Instead, it uses cassandra native protocol to set page size of the result > set. ( > https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v2.spec#L699-L730 > ) > When Cassandra sends the result back to the java driver, it includes a > some binary token. > This token represents paging state. To fetch the next page, the driver > re-executes the same > statement with original page size and paging state attached. If there is > another page available, > Cassandra responds with a new paging state that can be used to fetch it. > > You could also try reporting this issue on the Cassandra user mailing list. > > On Feb 12, 2015, at 8:35 AM, Eric Stevens <migh...@gmail.com> wrote: > > I don't know what the shape of the page state data is deep inside the > JavaDriver, I've actually tried to dig into that in the past and understand > it to see if I could reproduce it as a general purpose any-query kind of > thing. I gave up before I fully understood it, but I think it's actually a > handle to an in-memory state maintained by the coordinator, which is only > maintained for the lifetime of the statement (i.e. it's not stateless > paging). That would make it a bad candidate for stateless paging scenarios > such as REST requests where a typical setup would load balance across HTTP > hosts, never mind across coordinators. > > It shouldn't be too much work to abstract this basic idea for manual > paging into a general purpose class that takes List[ClusteringKeyDef[T, > O<:Ordering]], and can produce a connection agnostic PageState from a > ResultSet or Row, or accepts a PageState to produce a WHERE CQL fragment. > > > > Also RE: possibly multiple queries to satisfy a page - yes, that's > unfortunate. Since you're on 2.0.11, see Ondřej's answer to avoid it. > > On Thu, Feb 12, 2015 at 8:13 AM, Ajay <ajay.ga...@gmail.com> wrote: > >> Thanks Eric. I figured out the same but didn't get time to put it on the >> mail. Thanks. >> >> But it is highly tied up to how data is stored internally in Cassandra. >> Basically how partition keys are used to distribute (less likely to change. >> We are not directly dependence on the partition algo) and clustering keys >> are used to sort the data with in a partition( multi level sorting and >> henceforth the restrictions on the ORDER BY clause) which I think can >> change likely down the lane in Cassandra 3.x or 4.x in an different way for >> some better storage or retrieval. >> >> Thats said I am hesitant to implement this client side logic for >> pagination for a) 2+ queries might need more than one query to Cassandra. >> b) tied up implementation to Cassandra internal storage details which can >> change(though not often). c) in our case, we are building REST Apis which >> will be deployed Tomcat clusters. Hence whatever we cache to support >> pagination, need to be cached in a distributed way for failover support. >> >> It (pagination support) is best done at the server side like ROWNUM in >> SQL or better done in Java driver to hide the internal details and can be >> optimized better as server sends the paging state with the driver. >> >> Thanks >> Ajay >> On Feb 12, 2015 8:22 PM, "Eric Stevens" <migh...@gmail.com> wrote: >> >>> Your page state then needs to track the last ck1 and last ck2 you saw. >>> Pages 2+ will end up needing to be up to two queries if the first query >>> doesn't fill the page size. >>> >>> CREATE TABLE foo ( >>> partitionkey int, >>> ck1 int, >>> ck2 int, >>> col1 int, >>> col2 int, >>> PRIMARY KEY ((partitionkey), ck1, ck2) >>> ) WITH CLUSTERING ORDER BY (ck1 asc, ck2 desc); >>> >>> INSERT INTO foo (partitionkey, ck1, ck2, col1, col2) VALUES (1,1,1,1,1); >>> INSERT INTO foo (partitionkey, ck1, ck2, col1, col2) VALUES (1,1,2,2,2); >>> INSERT INTO foo (partitionkey, ck1, ck2, col1, col2) VALUES (1,1,3,3,3); >>> INSERT INTO foo (partitionkey, ck1, ck2, col1, col2) VALUES (1,2,1,4,4); >>> INSERT INTO foo (partitionkey, ck1, ck2, col1, col2) VALUES (1,2,2,5,5); >>> INSERT INTO foo (partitionkey, ck1, ck2, col1, col2) VALUES (1,2,3,6,6); >>> >>> If you're pulling the whole of partition 1 and your page size is 2, your >>> first page looks like: >>> >>> *PAGE 1* >>> >>> SELECT * FROM foo WHERE partitionkey = 1 LIMIT 2; >>> partitionkey | ck1 | ck2 | col1 | col2 >>> --------------+-----+-----+------+------ >>> 1 | 1 | 3 | 3 | 3 >>> 1 | 1 | 2 | 2 | 2 >>> >>> You got enough rows to satisfy the page, Your page state is taken from >>> the last row: (ck1=1, ck2=2) >>> >>> >>> *PAGE 2* >>> Notice that you have a page state, and add some limiting clauses on the >>> statement: >>> >>> SELECT * FROM foo WHERE partitionkey = 1 AND ck1 = 1 AND ck2 < 2 LIMIT 2; >>> partitionkey | ck1 | ck2 | col1 | col2 >>> --------------+-----+-----+------+------ >>> 1 | 1 | 1 | 1 | 1 >>> >>> Oops, we didn't get enough rows to satisfy the page limit, so we need to >>> continue on, we just need one more: >>> >>> SELECT * FROM foo WHERE partitionkey = 1 AND ck1 > 1 LIMIT 1; >>> partitionkey | ck1 | ck2 | col1 | col2 >>> --------------+-----+-----+------+------ >>> 1 | 2 | 3 | 6 | 6 >>> >>> We have enough to satisfy page 2 now, our new page state: (ck1 = 2, ck2 >>> = 3). >>> >>> >>> *PAGE 3* >>> >>> SELECT * FROM foo WHERE partitionkey = 1 AND ck1 = 2 AND ck2 < 3 LIMIT 2; >>> partitionkey | ck1 | ck2 | col1 | col2 >>> --------------+-----+-----+------+------ >>> 1 | 2 | 2 | 5 | 5 >>> 1 | 2 | 1 | 4 | 4 >>> >>> Great, we satisfied this page with only one query, page state: (ck1 = 2, >>> ck2 = 1). >>> >>> >>> *PAGE 4* >>> >>> SELECT * FROM foo WHERE partitionkey = 1 AND ck1 = 2 AND ck2 < 1 LIMIT 2; >>> (0 rows) >>> >>> Oops, our initial query was on the boundary of ck1, but this looks like >>> any other time that the initial query returns < pageSize rows, we just move >>> on to the next page: >>> >>> SELECT * FROM foo WHERE partitionkey = 1 AND ck1 > 2 LIMIT 2; >>> (0 rows) >>> >>> Aha, we've exhausted ck1 as well, so there are no more pages, page 3 >>> actually pulled the last possible value; page 4 is empty, and we're all >>> done. Generally speaking you know you're done when your first clustering >>> key is the only non-equality operator in the statement, and you got no rows >>> back. >>> >>> >>> >>> >>> >>> >>> On Wed, Feb 11, 2015 at 10:55 AM, Ajay <ajay.ga...@gmail.com> wrote: >>> >>>> Basically I am trying different queries with your approach. >>>> >>>> One such query is like >>>> >>>> Select * from mycf where condition on partition key order by ck1 asc, >>>> ck2 desc where ck1 and ck2 are clustering keys in that order. >>>> >>>> Here how do we achieve pagination support? >>>> >>>> Thanks >>>> Ajay >>>> On Feb 11, 2015 11:16 PM, "Ajay" <ajay.ga...@gmail.com> wrote: >>>> >>>>> >>>>> Hi Eric, >>>>> >>>>> Thanks for your reply. >>>>> >>>>> I am using Cassandra 2.0.11 and in that I cannot append condition like >>>>> last clustering key column > value of the last row in the previous batch. >>>>> It fails Preceding column is either not restricted or by a non-EQ >>>>> relation. >>>>> It means I need to specify equal condition for all preceding clustering >>>>> key columns. With this I cannot get the pagination correct. >>>>> >>>>> Thanks >>>>> Ajay >>>>> > I can't believe that everyone read & process all rows at once >>>>> (without pagination). >>>>> >>>>> Probably not too many people try to read all rows in a table as a >>>>> single rolling operation with a standard client driver. But those who do >>>>> would use token() to keep track of where they are and be able to resume >>>>> with that as well. >>>>> >>>>> But it sounds like you're talking about paginating a subset of data - >>>>> larger than you want to process as a unit, but prefiltered by some other >>>>> criteria which prevents you from being able to rely on token(). For this >>>>> there is no general purpose solution, but it typically involves you >>>>> maintaining your own paging state, typically keeping track of the last >>>>> partitioning and clustering key seen, and using that to construct your >>>>> next >>>>> query. >>>>> >>>>> For example, we have client queries which can span several >>>>> partitioning keys. We make sure that the List of partition keys generated >>>>> by a given client query List(Pq) is deterministic, then our paging >>>>> state is the index offset of the final Pq in the response, plus the >>>>> value of the final clustering column. A query coming in with a paging >>>>> state attached to it starts the next set of queries from the provided P >>>>> q offset where clusteringKey > the provided value. >>>>> >>>>> So if you can just track partition key offset (if spanning multiple >>>>> partitions), and clustering key offset, you can construct your next query >>>>> from those instead. >>>>> >>>>> On Tue, Feb 10, 2015 at 6:58 PM, Ajay <ajay.ga...@gmail.com> wrote: >>>>> >>>>>> Thanks Alex. >>>>>> >>>>>> But is there any workaround possible?. I can't believe that everyone >>>>>> read & process all rows at once (without pagination). >>>>>> >>>>>> Thanks >>>>>> Ajay >>>>>> On Feb 10, 2015 11:46 PM, "Alex Popescu" <al...@datastax.com> wrote: >>>>>> >>>>>>> >>>>>>> On Tue, Feb 10, 2015 at 4:59 AM, Ajay <ajay.ga...@gmail.com> wrote: >>>>>>> >>>>>>>> 1) Java driver implicitly support Pagination in the ResultSet >>>>>>>> (using Iterator) which can be controlled through FetchSize. But it is >>>>>>>> limited in a way that we cannot skip or go previous. The FetchState is >>>>>>>> not >>>>>>>> exposed. >>>>>>> >>>>>>> >>>>>>> Cassandra doesn't support skipping so this is not really a >>>>>>> limitation of the driver. >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> >>>>>>> [:>-a) >>>>>>> >>>>>>> Alex Popescu >>>>>>> Sen. Product Manager @ DataStax >>>>>>> @al3xandru >>>>>>> >>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>> send an email to java-driver-user+unsubscr...@lists.datastax.com. >>>>>>> >>>>>> >>>>> >>> > > >