RankAwarePromoter.java revision bf61e445cbe423cc2554b722b6dd38675015c36d
1a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney/* 2a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * Copyright (C) 2010 The Android Open Source Project 3a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * 4a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * Licensed under the Apache License, Version 2.0 (the "License"); 5a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * you may not use this file except in compliance with the License. 6a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * You may obtain a copy of the License at 7a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * 8a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * http://www.apache.org/licenses/LICENSE-2.0 9a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * 10a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * Unless required by applicable law or agreed to in writing, software 11a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * distributed under the License is distributed on an "AS IS" BASIS, 12a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * See the License for the specific language governing permissions and 14a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * limitations under the License. 15a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney */ 16a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 17a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinneypackage com.android.quicksearchbox; 18a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 1987e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringertimport android.util.Log; 2087e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert 2187e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringertimport java.util.ArrayList; 2287e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringertimport java.util.HashSet; 2387e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringertimport java.util.Iterator; 2487e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringertimport java.util.LinkedList; 25a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 26a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney/** 27a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * A promoter that gives preference to suggestions from higher ranking corpora. 28a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney */ 29a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinneypublic class RankAwarePromoter implements Promoter { 30a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 31bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert private static final boolean DBG = true; 32bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert private static final String TAG = "QSB.RankAwarePromoter"; 33bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert 34a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney private final HashSet<Corpus> mPromotedCorpora; 35a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 36a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney public RankAwarePromoter(Corpora corpora, CorpusRanker corpusRanker, int maxPromotedCorpora) { 37a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney // Create a set of the corpora we consider to be promoted. Note that we 38a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney // only do this once, even though these may change slightly during a session. 39bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert ArrayList<Corpus> orderedCorpora = corpusRanker.rankCorpora(corpora.getEnabledCorpora()); 40a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney int count = Math.min(orderedCorpora.size(), maxPromotedCorpora); 41a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney mPromotedCorpora = new HashSet<Corpus>(orderedCorpora.subList(0, count)); 42bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert if (DBG) Log.d(TAG, "Promoted: " + mPromotedCorpora); 43a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 44a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 45a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney private boolean isPromoted(Corpus corpus) { 46a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney return mPromotedCorpora.contains(corpus); 47a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 48a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 49a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney public void pickPromoted(SuggestionCursor shortcuts, ArrayList<CorpusResult> suggestions, 50a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney int maxPromoted, ListSuggestionCursor promoted) { 51a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 52bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert if (DBG) Log.d(TAG, "Available results: " + suggestions); 53bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert 54a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney // Split non-empty results into promoted and other, positioned at first suggestion 55a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney LinkedList<CorpusResult> promotedResults = new LinkedList<CorpusResult>(); 56a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney LinkedList<CorpusResult> otherResults = new LinkedList<CorpusResult>(); 57a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney for (int i = 0; i < suggestions.size(); i++) { 58a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney CorpusResult result = suggestions.get(i); 59a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney if (result.getCount() > 0) { 60a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney result.moveTo(0); 61a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney if (isPromoted(result.getCorpus())) { 62a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney promotedResults.add(result); 63a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } else { 64a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney otherResults.add(result); 65a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 66a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 67a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 68a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 69a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney // Pick 2 results from each of the promoted corpora 70a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney maxPromoted -= roundRobin(promotedResults, maxPromoted, 2, promoted); 71a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 72a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney // Then try to fill with the remaining promoted results 73a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney if (maxPromoted > 0 && !promotedResults.isEmpty()) { 74a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney int stripeSize = Math.max(1, maxPromoted / promotedResults.size()); 75a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney maxPromoted -= roundRobin(promotedResults, maxPromoted, stripeSize, promoted); 76a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney // We may still have a few slots left 77a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney maxPromoted -= roundRobin(promotedResults, maxPromoted, maxPromoted, promoted); 78a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 79a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 80a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney // Then try to fill with the rest 81a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney if (maxPromoted > 0 && !otherResults.isEmpty()) { 82a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney int stripeSize = Math.max(1, maxPromoted / otherResults.size()); 83a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney maxPromoted -= roundRobin(otherResults, maxPromoted, stripeSize, promoted); 84a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney // We may still have a few slots left 85a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney maxPromoted -= roundRobin(otherResults, maxPromoted, maxPromoted, promoted); 86a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 87bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert 88bf61e445cbe423cc2554b722b6dd38675015c36dBjorn Bringert if (DBG) Log.d(TAG, "Returning " + promoted.toString()); 89a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 90a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 91a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney /** 92a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * Promotes "stripes" of suggestions from each corpus. 93a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * 94a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * @param results the list of CorpusResults from which to promote. 95a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * Exhausted CorpusResults are removed from the list. 96a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * @param maxPromoted maximum number of suggestions to promote. 97a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * @param stripeSize number of suggestions to take from each corpus. 98a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * @param promoted the list to which promoted suggestions are added. 99a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * @return the number of suggestions actually promoted. 100a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney */ 101a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney private int roundRobin(LinkedList<CorpusResult> results, int maxPromoted, int stripeSize, 102a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney ListSuggestionCursor promoted) { 103a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney int count = 0; 104a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney if (maxPromoted > 0 && !results.isEmpty()) { 105a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney for (Iterator<CorpusResult> iter = results.iterator(); 106a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney count < maxPromoted && iter.hasNext();) { 107a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney CorpusResult result = iter.next(); 108a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney count += promote(result, stripeSize, promoted); 109a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney if (result.getPosition() == result.getCount()) { 110a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney iter.remove(); 111a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 112a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 113a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 114a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney return count; 115a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 116a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney 117a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney /** 118a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * Copies suggestions from a SuggestionCursor to the list of promoted suggestions. 119a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * 120a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * @param cursor from which to copy the suggestions 121a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * @param count maximum number of suggestions to copy 122a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * @param promoted the list to which to add the suggestions 123a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney * @return the number of suggestions actually copied. 124a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney */ 125a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney private int promote(SuggestionCursor cursor, int count, ListSuggestionCursor promoted) { 12687e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert if (count < 1 || cursor.getPosition() >= cursor.getCount()) { 12787e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert return 0; 12887e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert } 129a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney int i = 0; 13087e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert do { 131a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney promoted.add(new SuggestionPosition(cursor)); 132a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney i++; 13387e947cbd9f279a83337900ff8bbd5ab0a8dc455Bjorn Bringert } while (cursor.moveToNext() && i < count); 134a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney return i; 135a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney } 136a4cd9e7cdd5bdc6198ce73eed55696554a146514Bryan Mawhinney} 137