Conversation
When a 2i query's results are a list of keys. This change adds an optional request parameter to pb and http that, when set, will cause pairs of `key:index_value` to be returned as the result of a 2i query. Has no effect on MapReduce. Uses capabilities for rolling upgrade situations.
Adds a `max_results` option to PB and HTTP 2i endpoints for limiting the number of results returned for a 2i query. Will return an opaque `continuation` if there are at least `max_results` results returned. A subsequent query that includes the `continuation` as a parameter will return the next `max_results` results. The results will be returned sorted ascending. In the case of $key and $bucket queries, and equals queries, the results will be sorted by primary key In the case of range queries the results will be sorted by index value. Since the values must be returned from the backend for sorting, there is a further option `return_terms` that will cause the indexed terms to be returned to the user also, where relevant (range queries on index fields.) Sorting is performed by the module `sms.erl` originally written by Reid Draper. It is used as a buffer by `riak_kv_index_fsm`. A new vnode function `stop_fold` has been added so the fsm can tell the backend to break out of the fold when enough results have been gathered. The option to stream 2i results has also been added. Adding the `stream` option to either HTTP or PB queries will cause the API endpoints to return chunks of results as they are received from the fsm This can lead to much lower perceived latencies as the application recieves the first results of a large set much sooner. An example HTTP query: `curl "http://127.0.0.1:10018/buckets/2ibucket/index/field2_int/1/100?return_terms=true"` Will return the first 100 {value, key} pairs for the `field2_int` index, sorted by value. If there are 100 results returned, it will also return an opaque `continuation` that may be sumbitted to continue the query: `curl "http://127.0.0.1:10018/buckets/2ibucket/index/field2_int/1/100?return_terms=true&continuation=some_gibberish_looking_value"` A further `continuation` maybe returned with the results.
Spotted lager info message left over from dev, excised it.
I have no idea how. Tests passed, then they didn't. I guess a rebase went wrong.
We use keys for the range on buckets
The wrong paramter was used to match in the function head for to_first _key
Even though not required, backend feature parity makes sense, more so if the features are to be added to `backend_eqc`. Refactor `index | object _key_in_range` funs for common use. Removed stray debugging `lager:info/1` message.
There was a problem hiding this comment.
Don't forget to stick a licence header or the lawyers will get you!
* Allow add_results to be called repeatedly with done, it's harmless. * Allow sms to be called when all sources are done without crashing.
src/riak_kv_vnode.erl
Outdated
There was a problem hiding this comment.
We now have a bit of a misnomer here. Consider changing to something like handle_coverage_fold instead now that we do both key only and key/value folds?
There was a problem hiding this comment.
I'm not sure. I get your meaning…but…hmmm…I think really a deeper refactor is needed. The query should dictate the fold type, probably the backend should decide. I see this as a hack / halfway house. Changing the name might even add to the confusion? I totally agree with you, but think there is some more discussion to be had.
src/riak_kv_pb_csbucket.erl
Outdated
There was a problem hiding this comment.
I believe this is correct, but consider doing Count >= MaxResults for total future proofing paranoia. Same with riak_kv_pb_index actually.
|
There is one funny side effect of the way max results and continuations work: Currently we make no attempt to deduplicate results from a 2i query. So, if item 1 is indexed on field f1 for values 1,2,3, and you do a range query from 1 to 3, you will get the same item 3 times. Now, if you specify max results as 2, you get the value twice, plus a continuation. If you query the continuation, you get nothing. Since we are now sorting the results, deduplicating becomes very cheap. I'm wondering if we should start doing it. On the other hand, if users rely on this property and use the number of duplicates for something, continuations might break that. Thoughts? |
|
More on the duplicates being dropped behaviour: if return_terms is true the duplicates that we are dropping may contain information useful to the client. Or at least it's easier to imagine they might care about that, since some terms will sometimes be retrieved, sometimes lost. |
|
I don't understand. Can you provide a test or some minimal set of data and a query that reproduce the condition, please? |
|
https://gist.github.com/engelsanchez/5630275 I'm not saying this is bad or unintended. Just that it might interfere with what the users of return_terms might want to do with that. Maybe ask them directly if it matters? |
|
It is bad and unintended. I really hadn't noticed it or thought of it. I'm not sure what the answer it, except to expose the |
|
OK. I think this is a straight up bug from considering the key and the index value in isolation. Let me work on it this morning, I have some ideas. |
A bug found by @engelsanchez, where `start_incl` being false (when using a continuation, for example) led to in range values being excluded as the key was checked in isolation.
|
Pooshed a fix for the dropped-duplicate-key-after-continuation bug, (good catch BTW! Glad we didn't ship that.) Pooshed test for same to riak_test. Would you say now is a good time to address your other comments (i.e. are you through with the majority of the review?) |
|
I've verified the fix works on my example. Good work man! Simple, small and effective fix. Will keep banging on it to see what else I can find. |
Clean-up and slightly optimise the index fsm to not recalculate the same list length more than once. Shortcut sending the `stop_fold` message where possible (i.e. when we notice the have enough results). Add JSON error to 2i HTTP strem Update all copyright notices Normalise boolean paramters to strict true | false
|
A couple more things: remember to look at my branch adding an EQC test for sms, which also contains a couple of proposed edge case fixes: https://github.com/basho/riak_kv/commits/eas-add-sms-eqc And you will need to merge from master before the PR gets its green button again (there is a little conflict in riak_kv_app where capabilities are added). Please do that before the final 👍 so that I can go over the final version of the code. |
Conflicts: src/riak_kv_app.erl
|
I'm having trouble using max_results and return_terms together through the HTTP interface Also, validation doesn't seem to kick in for the second parameter. Maybe I'm doing something stupid, but I haven't figured it out. I'll debug this more right after lunch. |
|
This is why I hate changes on review. I tested this stuff in the past. Ok. I'll add some more tests to riak_test and see what is up. Thanks. |
|
Huh. Works for me. I enquoted my url+query params thussly: and and and Are all your branches up-to-date? I'll push the latest, which merges master and your EQC test (thanks for that, great work!) /me shrugs |
|
Yep. I tried on the browser and it works fine too. Nothing to see here, move along, nevermind... Sorry |
|
Heh, better safe, no worries. |
|
Ok, I think we can call it a day. I believe all comments were addressed. New testing has not uncovered any new problems. Ship it! |
Conflicts: src/riak_kv_app.erl src/riak_kv_wm_raw.hrl
…place
Failing query test case:
V1 = backend_eqc:init_backend(riak_kv_eleveldb_backend,false, [{data_root,"test/eleveldb-backend"}]).
riak_kv_eleveldb_backend:put(<<"b2">>,<<"k1">>, [{add,<<"k_int">>,0}], <<110>>, V1).
riak_kv_eleveldb_backend:fold_keys(fun(B, K, Acc) -> [{B, K}|Acc] end, [],
Return value:
[{index,<<"b2">>,{range,<<"k_int">>,0,0}}], V1).
@rdb Please check to see how much effort vs. value might be required
to address the TODO comment. If it's too much work now, then please
create an issue for fixing & removing that TODO item so that the matter
doesn't get lost.
After this commit, tested via:
P = backend_eqc : property ( riak_kv_eleveldb_backend , false , [ { data_root , "test/eleveldb-backend" } ] ).
eqc:quickcheck(eqc:testing_time(4*300, P)).
[...]
OK, passed 9670 tests
|
From the commit log: @rdb Please check to see how much effort vs. value might be required |
|
Oh, and the bug fixed by commit 6934d65 is something that only pops up every few minutes, in my experience with the backend_eqc test. The namespace (bucket + key + index) is likely too big to hit a case where a bucket + key + index is written and then sometime later a fold_keys is attempted with a query on the exact same index. So, whenever a developer plays with areas that would affect the code that this test exercises, it would be extremely wise to run the backend_eqc test for a much longer period of time than the usual "make test" does. See my comment on that commit for an example. |
|
Awesome @slfritchie. Thanks for finding and fixing. I think I'll fix that test properly during this testing cycle (add all the new query types, make it use V2 queries etc.) Thanks again. It was on the list to update the test, but time is cruel. |
Adds a
max_resultsoption to PB and HTTP 2i endpoints for limitingthe number of results returned for a 2i query. Will return an opaque
continuationif there aremax_resultsresults returned. Asubsequent query that includes the
continuationas a parameter willreturn the next
max_resultsresults.The results will be returned sorted ascending. In the case of $key
and $bucket queries, and equals queries, the results will be sorted by
primary key In the case of range queries the results will be sorted by
index value, then primary key. Since the values must be returned from the backend for
sorting, there is a further option
return_termsthat will cause theindexed terms to be returned to the user also, where relevant (range
queries on index fields.)
Sorting is performed by the module
sms.erloriginally written by ReidDraper. It is used as a buffer by
riak_kv_index_fsm.A new vnode function
stop_foldhas been added so the fsm can tellthe backend to break out of the fold when enough results have been
gathered.
The option to stream 2i results has also been added. Adding the
streamoption to either HTTP or PB queries will cause the APIendpoints to return chunks of results as they are received from the
fsm This can lead to much lower perceived latencies as the application
recieves the first results of a large set much sooner.
An example HTTP query:
curl "http://127.0.0.1:10018/buckets/2ibucket/index/field2_int/1/999?return_terms=true&max_results=100"Will return the first 100 {value, key} pairs for the
field2_intindex, sorted by value, then primary key. If there are 100 results returned, it will
also return an opaque
continuationthat may be sumbitted to continuethe query:
curl "http://127.0.0.1:10018/buckets/2ibucket/index/field2_int/1/999?return_terms=true&continuation=some_gibberish_looking_value&max_results=100"A further
continuationmaybe returned with the results.Riak tests can be found at https://github.com/basho/riak_test/tree/pt29-2i-pagination
Riak-Erlang-Client support at https://github.com/basho/riak-erlang-client/tree/pt29-2i-pagination
NOTE: requires
https://github.com/basho/riak_core/tree/pt29-2i-pagination
https://github.com/basho/riak_pb/tree/pt29-2i-pagination