How to change data in sorted set? - redis

I use sorted set data type in Redis.
I add data with command zadd. Adding data is JSON format.
How I can change value in this sorted set by score?
I need get JSON value and change one field and after update this sorted set.
I tried to add againg data with the same score, but I get dublicates

It's simple!
ZREM key data;
ZADD key score newdata;
You simply cannot UPDATE an element in SET structure. It's not possible by definition! Like I cannot EAT a cup of water, I can only DRINK it ^_^
Reply if you have any further problems.
By the way, I don't know your application need, but I have a strong feeling that SORTED SET is unsuitable for your application senario.

One does not update a set's (sorted or not) members. You'll have to remove the old member and add the new (updated JSON) in its place with the relevant score. You could wrap this in Lua or a WATCH/MULTI/EXEC block for atomicity.

You could remove first by score if you're using the list as a key (score) => value store.
ZREMRANGEBYSCORE key score score
ZADD key score data

Related

Redis - Sort ID's based on Names in another Set

I am using multiple redis sets, hashes and Sorted sets for my use-case.
Suppose I am having a HASH set which stores ID and its corresponding object. (Project ID and its Content)
I have sets which contain list of ID's (List of ProjectIDs)
I have sorted sets which will sortBy DateTime fields and other Integer scores.
(Sort by DeadLine, Created etc and also by Project Name).
I also created a Sorted Set as my use-case needs Sort By Name (say Project Name). I created Project Name Sorted Set (ProjectName:ID as value and 0 as score).
So my requirement is that I need to sort my set (which contain ID's) based on Project Name in DESC or ASC.
How to achieve this??
Read the documentation about SORT - it should be something like SORT nameofzset BY nosort GET nameofhash->*. Even better, learn how to write Lua scripts and execute them with EVAL.

NSFetchedResultsController to return objects with unique property

I have a properly set up NSFetchedResultsController that returns all the objects I want. However, I want to set it up so that it returns only objects that are unique by ID value, because there are several duplicate objects that have the same ID but other different properties in the DB.
I tried to set it up like the documentation says and ended up with this result:
fetchRequest.returnsDistinctResults = YES;
fetchRequest.propertiesToFetch = #[#"eventCategoryID", #"eventName", #"eventID", #"eventPeopleCount", #"eventPrice", #"eventCrewCount", #"eventStartDateTS", #"eventImageURL", #"shouldShowFriends", #"isLiked"];
However they say that you have to use this property only with NSDictionaryResultType. And moreover, it gives me a strange crash.
What are the approaches to make objects returned by NSFetchedResultsController filtered so as to have a custom unique property like ID?
So you want to find all the objects where the ID property is unique? Then yes, NSDictionaryResultType is the way to go. I think you will need two fetches, though.
First, build a fetch request to retrieve all of the ID values, and a count for each value. Use NSExpressionDescription to apply the #count function to your results, and use an NSDictionaryResultType. Group by ID. A step by step example is at http://mattconnolly.wordpress.com/2012/06/21/ios-core-data-group-by-and-count-results/.
Now you'll have a dictionary with keys for ID and the count of that ID. Filter that dictionary so that you only have IDs where the count was 1, and extract just those ID values. Now you can build a second fetch request based on ID IN ... your array of singleton IDs.
It might be possible to build a more complicated original fetch request to return only the count=1 IDs.

Redis Sets - date added

I currently have a Redis Set and I'm not sure if this is possible but thought I'd ask just in case someone knows of a way around it. Is it possible to add a date of when a new element for a key is created when using 'SADD' command?
I've tried searching the web but I can't find anything, which tells me its not possible. Is there another way of doing this? Something like the below and then being able to get the date the element was created?
SADD my:key:string "1000", Time.now
Use a Sorted Set instead of a Set. Using the timestamp as a score will allow you to retrieve your values ordered by date, values for a given date, values after of before a given date, etc. Or of course just the date for the value.
ZADD myzset 12345678 "my value"
In order to set the date of an element save the element in form of json :
SADD mset "{value:1000,created:18-03-2014}"
So when you retrieve the element its creation date will be also be retrieved.

Return new, unique items from redis set

I am using redis to store a list of items in a set. I add a very similar list to the set periodically, and obviously, the sorted set only adds new items if they don't already exist. Is there a way to get that list of new items that were just added? The ones that didn't already exist in the set?
Danke schoen.
ZADD command, if called with one score/member pair, returns 1 if member was new and 0 if it already existed. You can use this. Add elements one by one and check return values.
In addition to iterating over your new list as described by Sergio, you could store the keys from your sorted set in a set, store your new list in a set and do an sdiff or sdiffstore on them to get the difference.
Which route will be better is a judgement call for you based in your code and data set. If the new list is short if probably go with simple iteration using the zadd command like Sergio describes. Otherwise I'd test to see which is better for my use case.

Boosting Multi-Value Fields

I have a set of documents containing scored items that I'd like to index. Our data structure looks like:
Document
ID
Text
List<RelatedScore>
RelatedScore
ID
Score
My first thought was to add each RelatedScore as a multi-value field using the Boost property of the Field to modify the value of the particular score when searching.
foreach (var relatedScore in document.RelatedScores) {
var field = new Field("RelatedScore", relatedScore.ID,
Field.Store.YES, Field.Index.UN_TOKENIZED);
field.SetBoost(relatedScore.Score);
luceneDoc.Add(field);
}
However, it appears that the "Norm" that is calculated applies to the entire multi-field - all the RelatedScore" values for a document will end up having the same score.
Is there a mechanism in Lucene to allow for this functionality? I would rather not create another index just to account for this - it feels like there should be a way using a single index. If there isn't a means to accomplish this, a few ideas that we have to compensate are :
Insert the multi-value field items in order of descending value. Then somehow add a positional-aware analysis to assign higher boost/score to the first items in the field.
Add a high value score multiple times to the field. So, a RelatedScore with Score==1 might be added three times, while a RelatedScore with Score==.3 would only be added once.
Both of these will result in a loss of search fidelity on these fields, yes, but they may be good enough. Any thoughts on this?
This appears to be a use case for Payloads. I'm not sure if this is available in Lucene.NET, as I've only used the Java version.
Another hacky way to do this, if the absolute values of the scores aren't that important, is to discretize them (place them in buckets based on value) and create a field for each bucket. So if you have scores that range from 1 to 100, create say, 10 buckets called RelatedScore0_10, RelatedScore10_20, etc, and for any document that has a RelatedScore in that bucket, add a "true" value in that field. Then for every search that gets executed tack on an OR query like:
(RelatedScore0_10:true^1 RelatedScore10_20:true^2 ...)
The nice thing about this is that you can tweak the boost values for each one of your buckets on the fly. Otherwise you'd need to reindex to change the field norm (boost) values for each field.
If you use Lucene.Net you might not have payloads functionality yet. What you can do is convert 0-100 relevancy score to a bucket from 1-10 (integer division by 10), then add each indexed value that many times (but only store value once). Then if you search for that field, lucene built-in scoring will take into account frequency of indexed field (it will be indexed 1-10 times based on relevance). Therefore results can be sorted by variable relevance.
foreach (var relatedScore in document.RelatedScores) {
// get bucket for relevance...
int bucket=relatedScore.Score / 10;
var field = new Field("RelatedScore", relatedScore.ID,
Field.Store.YES, Field.Index.UN_TOKENIZED);
luceneDoc.Add(field);
// add more instances of field but only store the first one above...
for(int i=0;i<bucket;i++)
{
luceneDoc.Add(new Field("RelatedScore", relatedScore.ID,
Field.Store.NO, Field.Index.UN_TOKENIZED));
}
}