DefaultCorpusRanker.java revision 22da5e41bec9a5d36388c1e6f99bca392c3ac63e
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.quicksearchbox;
18
19import com.android.quicksearchbox.util.AsyncCache;
20import com.android.quicksearchbox.util.Consumer;
21
22import android.database.DataSetObserver;
23import android.util.Log;
24
25import java.util.ArrayList;
26import java.util.Collection;
27import java.util.Collections;
28import java.util.Comparator;
29import java.util.List;
30import java.util.Map;
31
32/**
33 * A corpus ranker that uses corpus scores from the shortcut repository to rank
34 * corpora.
35 */
36public class DefaultCorpusRanker implements CorpusRanker {
37
38    private static final boolean DBG = false;
39    private static final String TAG = "QSB.DefaultCorpusRanker";
40
41    private final ShortcutRepository mShortcuts;
42
43    private final Corpora mCorpora;
44
45    // Cached list of ranked corpora.
46    private final RankedCorporaCache mRankedCorpora;
47
48    /**
49     * Creates a new default corpus ranker.
50     *
51     * @param corpora Corpora to rank.
52     * @param shortcuts Shortcut repository for getting corpus scores.
53     */
54    public DefaultCorpusRanker(Corpora corpora, ShortcutRepository shortcuts) {
55        mCorpora = corpora;
56        mCorpora.registerDataSetObserver(new CorporaObserver());
57        mShortcuts = shortcuts;
58        mRankedCorpora = new RankedCorporaCache();
59    }
60
61    public void getRankedCorpora(Consumer<List<Corpus>> consumer) {
62        mRankedCorpora.get(consumer);
63    }
64
65    public void clear() {
66        mRankedCorpora.clear();
67    }
68
69    private class CorporaObserver extends DataSetObserver {
70        @Override
71        public void onChanged() {
72            clear();
73        }
74    }
75
76    private class RankedCorporaCache extends AsyncCache<List<Corpus>> {
77
78        protected void create() {
79            mShortcuts.getCorpusScores(new Consumer<Map<String,Integer>>(){
80                public boolean consume(Map<String, Integer> clickScores) {
81                    Collection<Corpus> enabledCorpora = mCorpora.getEnabledCorpora();
82                    if (DBG) Log.d(TAG, "Ranking: " + enabledCorpora);
83                    ArrayList<Corpus> ordered = new ArrayList<Corpus>(enabledCorpora);
84                    Collections.sort(ordered, new CorpusComparator(clickScores));
85
86                    if (DBG) Log.d(TAG, "Click scores: " + clickScores);
87                    if (DBG) Log.d(TAG, "Ordered: " + ordered);
88
89                    store(ordered);
90                    return true;
91                }
92            });
93        }
94
95    }
96
97    private static class CorpusComparator implements Comparator<Corpus> {
98        private final Map<String,Integer> mClickScores;
99
100        public CorpusComparator(Map<String,Integer> clickScores) {
101            mClickScores = clickScores;
102        }
103
104        public int compare(Corpus corpus1, Corpus corpus2) {
105            boolean corpus1IsDefault = corpus1.isCorpusDefaultEnabled();
106            boolean corpus2IsDefault = corpus2.isCorpusDefaultEnabled();
107
108            if (corpus1IsDefault != corpus2IsDefault) {
109                // Default corpora always come before non-default
110                return corpus1IsDefault ? -1 : 1;
111            }
112
113            // Then by descending score
114            int scoreDiff = getCorpusScore(corpus2) - getCorpusScore(corpus1);
115            if (scoreDiff != 0) {
116                return scoreDiff;
117            }
118
119            // Finally by name
120            return corpus1.getLabel().toString().compareTo(corpus2.getLabel().toString());
121        }
122
123        /**
124         * Scores a corpus. Higher score is better.
125         */
126        private int getCorpusScore(Corpus corpus) {
127            // Web corpus always comes first
128            if (corpus.isWebCorpus()) {
129                return Integer.MAX_VALUE;
130            }
131            // Then use click score
132            return getClickScore(corpus);
133        }
134
135        private int getClickScore(Corpus corpus) {
136            if (mClickScores == null) return 0;
137            Integer clickScore = mClickScores.get(corpus.getName());
138            return clickScore == null ? 0 : clickScore;
139        }
140    }
141
142}
143