I have thousands of items in a table. Each item has a numeric attribute score. What I want to do:
- Given some
targetScore, select all items wheretargetScore - n <= score <= targetScore + n(I got this part working). - Return only the first
jelements wherej := ABS(targetScore - score)in ASC order.
Since the table is somewhat large, and will only grow over time, I'm hoping to have a way to delegate step #2 above to the DynamoDB engine. I'm currently selecting all item IDs from step #1, doing the computation for step #2 in process, then selecting the resulting items on a subsequent query.
You don't really need step 1 to get step 2. I'm assuming that
scoreis a sort key in your setup.In step 2, you want to sort the items by
abs(targetScore - score)and take thejlowest ones.Although DynamoDB doesn't have any direct way to do that, the definition of the absolute value makes it quite easy to do. First, observe that `abs(targetScore - score) is defined as follows: It is:
targetScore - scoreifscore <= targetScorescore - targetScoreifscore >= targetsScoreSo the items with the smallest abs are either items with a score higher than
targetScorebut as low as possible, or items with a score lower thantargetScore, but as high as possible.So, you can do two separate DynamoDB queries:
jitems withscore >= targetScore, sorted in increasingscore.jitems withscore < targetScore, sorted in decreasingscore.DynanoDB can do both queries for you efficiently and cheaply - it involves a
Querywith aKeyConditionsparameter and aLimit, andScanIndexForwardto do decreasing sorting. But no expensive and inefficientFilterExpression!Once you have the
jsmallest items of each type 1 and type 2, all that remains is to pick the overalljsmallest items from these2*jitems we got.