public void TestUserRescorer() { Rescorer <User> rescorer = NullRescorer <User> .Instance; Assert.IsNotNull(rescorer); User user = new GenericUser <String>("test", new List <Preference>()); Assert.AreEqual(1.0, rescorer.Rescore(user, 1.0)); Assert.AreEqual(1.0, rescorer.Rescore(null, 1.0)); Assert.AreEqual(0.0, rescorer.Rescore(user, 0.0)); Assert.IsTrue(Double.IsNaN(rescorer.Rescore(user, Double.NaN))); }
public void TestItemRescorer() { Rescorer <Item> rescorer = NullRescorer <Item> .Instance; Assert.IsNotNull(rescorer); Item item = new GenericItem <String>("test"); Assert.AreEqual(1.0, rescorer.Rescore(item, 1.0)); Assert.AreEqual(1.0, rescorer.Rescore(null, 1.0)); Assert.AreEqual(0.0, rescorer.Rescore(item, 0.0)); Assert.IsTrue(Double.IsNaN(rescorer.Rescore(item, Double.NaN))); }
public virtual void TestBasic() { // create a sort field and sort by it (reverse order) Query query = new TermQuery(new Term("body", "contents")); IndexReader r = searcher.IndexReader; // Just first pass query TopDocs hits = searcher.Search(query, 10); AreEqual(3, hits.TotalHits); AreEqual("3", r.Document(hits.ScoreDocs[0].Doc).Get("id")); AreEqual("1", r.Document(hits.ScoreDocs[1].Doc).Get("id")); AreEqual("2", r.Document(hits.ScoreDocs[2].Doc).Get("id")); // Now, rescore: Expression e = JavascriptCompiler.Compile("sqrt(_score) + ln(popularity)"); SimpleBindings bindings = new SimpleBindings(); bindings.Add(new SortField("popularity", SortField.Type_e.INT)); bindings.Add(new SortField("_score", SortField.Type_e.SCORE)); Rescorer rescorer = e.GetRescorer(bindings); hits = rescorer.Rescore(searcher, hits, 10); AreEqual(3, hits.TotalHits); AreEqual("2", r.Document(hits.ScoreDocs[0].Doc).Get("id")); AreEqual("1", r.Document(hits.ScoreDocs[1].Doc).Get("id")); AreEqual("3", r.Document(hits.ScoreDocs[2].Doc).Get("id")); string expl = rescorer.Explain(searcher, searcher.Explain(query, hits.ScoreDocs[0].Doc), hits.ScoreDocs[0].Doc).ToString(); // Confirm the explanation breaks out the individual // variables: IsTrue(expl.Contains("= variable \"popularity\"")); // Confirm the explanation includes first pass details: IsTrue(expl.Contains("= first pass score")); IsTrue(expl.Contains("body:contents in")); }
public int Compare(RecommendedItem o1, RecommendedItem o2) { double rescored1 = rescorer.Rescore(o1.Item, o1.Value); double rescored2 = rescorer.Rescore(o2.Item, o2.Value); Debug.Assert(!double.IsNaN(rescored1)); Debug.Assert(!double.IsNaN(rescored2)); if (rescored1 < rescored2) { return(1); } else if (rescored1 > rescored2) { return(-1); } else { return(0); } }
public double Estimate(Item item) { Pair <Item, Item> pair = new Pair <Item, Item>(toItem, item); if (rescorer.IsFiltered(pair)) { return(Double.NaN); } double originalEstimate = correlation.GetItemCorrelation(toItem, item); return(rescorer.Rescore(pair, originalEstimate)); }
public double Estimate(User user) { Pair <User, User> pair = new Pair <User, User>(toUser, user); if (rescorer.IsFiltered(pair)) { return(Double.NaN); } double originalEstimate = correlation.GetUserCorrelation(toUser, user); return(rescorer.Rescore(pair, originalEstimate)); }
/** * {@inheritDoc} */ public override IList <RecommendedItem> Recommend(Object userID, int howMany, Rescorer <Item> rescorer) { if (userID == null || rescorer == null) { throw new ArgumentNullException("userID or rescorer is null"); } if (howMany < 1) { throw new ArgumentException("howMany must be at least 1"); } CheckClustersBuilt(); if (log.IsDebugEnabled) { log.Debug("Recommending items for user ID '" + userID + '\''); } IList <RecommendedItem> recommended; topRecsByUserID.TryGetValue(userID, out recommended); if (recommended == null) { recommended = new List <RecommendedItem>(); return(recommended); } User theUser = this.DataModel.GetUser(userID); List <RecommendedItem> rescored = new List <RecommendedItem>(recommended.Count); // Only add items the user doesn't already have a preference for. // And that the rescorer doesn't "reject". foreach (RecommendedItem recommendedItem in recommended) { Item item = recommendedItem.Item; if (rescorer.IsFiltered(item)) { continue; } if (theUser.GetPreferenceFor(item.ID) == null && !double.IsNaN(rescorer.Rescore(item, recommendedItem.Value))) { rescored.Add(recommendedItem); } } rescored.Sort(new ByRescoreComparator(rescorer)); return(rescored); }
public double Estimate(Item item) { RunningAverage average = new FullRunningAverage(); foreach (Item toItem in toItems) { Pair <Item, Item> pair = new Pair <Item, Item>(toItem, item); if (rescorer.IsFiltered(pair)) { continue; } double estimate = correlation.GetItemCorrelation(toItem, item); estimate = rescorer.Rescore(pair, estimate); average.AddDatum(estimate); } return(average.Average); }
public static IList <RecommendedItem> GetTopItems(int howMany, IEnumerable <Item> allItems, Rescorer <Item> rescorer, Estimator <Item> estimator) { if (allItems == null || rescorer == null || estimator == null) { throw new ArgumentNullException("argument is null"); } LinkedList <RecommendedItem> topItems = new LinkedList <RecommendedItem>(); bool full = false; foreach (Item item in allItems) { if (item.IsRecommendable && !rescorer.IsFiltered(item)) { double preference = estimator.Estimate(item); double rescoredPref = rescorer.Rescore(item, preference); LinkedListNode <RecommendedItem> node = topItems.Last; if (!Double.IsNaN(rescoredPref) && (!full || rescoredPref > node.Value.Value)) { // I think this is faster than Collections.binarySearch() over a LinkedList since our // comparisons are cheap, which binarySearch() economizes at the expense of more traversals. // We also know that the right position tends to be at the end of the list. while (node != null && node.Previous != null) { node = node.Previous; if (rescoredPref <= node.Value.Value) { node = node.Next; break; } if (node == topItems.First) { break; } } RecommendedItem newItem = new GenericRecommendedItem(item, rescoredPref); if (node == null) { topItems.AddFirst(newItem); } else if (topItems.Count == 1) { // special handling in this case is to avoid problems // with negative preferences. Imagine -0.3 being added // first followed by -0.6. If we simply did AddAfter, // those items would be out of sequence - cc if (rescoredPref > node.Value.Value) { topItems.AddAfter(node, newItem); } else { topItems.AddBefore(node, newItem); } } else { topItems.AddAfter(node, newItem); } if (full) { topItems.RemoveLast(); } else if (topItems.Count > howMany) { full = true; topItems.RemoveLast(); } } } } List <RecommendedItem> result = new List <RecommendedItem>(topItems.Count); foreach (RecommendedItem item in topItems) { result.Add(item); } return(result); }
public static List <User> GetTopUsers(int howMany, IEnumerable <User> allUsers, Rescorer <User> rescorer, Estimator <User> estimator) { LinkedList <SimilarUser> topUsers = new LinkedList <SimilarUser>(); bool full = false; foreach (User user in allUsers) { if (rescorer.IsFiltered(user)) { continue; } double similarity = estimator.Estimate(user); double rescoredSimilarity = rescorer.Rescore(user, similarity); LinkedListNode <SimilarUser> node = topUsers.Last; if (!double.IsNaN(rescoredSimilarity) && (!full || rescoredSimilarity > node.Value.Similarity)) { //SimilarUser _user = new SimilarUser(user, similarity); SimilarUser _user = new SimilarUser(user, rescoredSimilarity); if (node == null) { topUsers.AddLast(_user); } else if (node.Previous == null) // 1 node { if (rescoredSimilarity > node.Value.Similarity) { topUsers.AddAfter(node, _user); } else { topUsers.AddBefore(node, _user); } } else { while (node != null && node.Previous != null && (node != topUsers.First)) { node = node.Previous; if (rescoredSimilarity <= node.Value.Similarity) { topUsers.AddBefore(node, _user); break; } } } if (full) { topUsers.RemoveLast(); } else if (topUsers.Count > howMany) { full = true; topUsers.RemoveLast(); } } } List <User> result = new List <User>(topUsers.Count); foreach (SimilarUser similarUser in topUsers) { result.Add(similarUser.User); } return(result); }