OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/autocomplete/history_contents_provider.h" | 5 #include "chrome/browser/autocomplete/history_contents_provider.h" |
6 | 6 |
7 #include "base/callback.h" | 7 #include "base/callback.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
11 #include "chrome/browser/autocomplete/autocomplete_match.h" | 11 #include "chrome/browser/autocomplete/autocomplete_match.h" |
12 #include "chrome/browser/bookmarks/bookmark_model.h" | 12 #include "chrome/browser/bookmarks/bookmark_model.h" |
13 #include "chrome/browser/bookmarks/bookmark_utils.h" | 13 #include "chrome/browser/bookmarks/bookmark_utils.h" |
14 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
15 #include "chrome/common/url_constants.h" | 15 #include "chrome/common/url_constants.h" |
16 #include "googleurl/src/url_util.h" | 16 #include "googleurl/src/url_util.h" |
17 #include "net/base/net_util.h" | 17 #include "net/base/net_util.h" |
18 | 18 |
19 using base::TimeTicks; | 19 using base::TimeTicks; |
20 using history::HistoryDatabase; | |
20 | 21 |
21 namespace { | 22 namespace { |
22 | 23 |
23 // Number of days to search for full text results. The longer this is, the more | 24 // Number of days to search for full text results. The longer this is, the more |
24 // time it will take. | 25 // time it will take. |
25 const int kDaysToSearch = 30; | 26 const int kDaysToSearch = 30; |
26 | 27 |
27 // When processing the results from the history query, this structure points to | 28 } // end namespace |
28 // a single result. It allows the results to be sorted and processed without | |
29 // modifying the larger and slower results structure. | |
30 struct MatchReference { | |
31 MatchReference(const history::URLResult* result, int relevance) | |
32 : result(result), | |
33 relevance(relevance) { | |
34 } | |
35 | 29 |
36 const history::URLResult* result; | 30 HistoryContentsProvider::MatchReference::MatchReference( |
37 int relevance; // Score of relevance computed by CalculateRelevance. | 31 const history::URLResult* result, |
38 }; | 32 int relevance, |
39 | 33 float confidence) |
40 // This is a > operator for MatchReference. | 34 : result(result), |
41 bool CompareMatchRelevance(const MatchReference& a, const MatchReference& b) { | 35 relevance(relevance), |
42 if (a.relevance != b.relevance) | 36 confidence(confidence) { |
43 return a.relevance > b.relevance; | |
44 | |
45 // Want results in reverse-chronological order all else being equal. | |
46 return a.result->last_visit() > b.result->last_visit(); | |
47 } | 37 } |
48 | 38 |
49 } // namespace | 39 // static |
50 | 40 bool HistoryContentsProvider::MatchReference::CompareRelevance( |
51 using history::HistoryDatabase; | 41 const HistoryContentsProvider::MatchReference& lhs, |
42 const HistoryContentsProvider::MatchReference& rhs) { | |
43 if (lhs.relevance != rhs.relevance) | |
44 return lhs.relevance > rhs.relevance; | |
45 return lhs.result->last_visit() > rhs.result->last_visit(); | |
46 } | |
52 | 47 |
53 HistoryContentsProvider::HistoryContentsProvider(ACProviderListener* listener, | 48 HistoryContentsProvider::HistoryContentsProvider(ACProviderListener* listener, |
54 Profile* profile, | 49 Profile* profile, |
55 bool body_only) | 50 bool body_only) |
56 : HistoryProvider(listener, profile, "HistoryContents"), | 51 : HistoryProvider(listener, profile, "HistoryContents"), |
57 star_title_count_(0), | 52 star_title_count_(0), |
58 star_contents_count_(0), | 53 star_contents_count_(0), |
59 title_count_(0), | 54 title_count_(0), |
60 contents_count_(0), | 55 contents_count_(0), |
61 input_type_(AutocompleteInput::INVALID), | 56 input_type_(AutocompleteInput::INVALID), |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
180 | 175 |
181 // Make the result references and score the results. | 176 // Make the result references and score the results. |
182 std::vector<MatchReference> result_refs; | 177 std::vector<MatchReference> result_refs; |
183 result_refs.reserve(results_.size()); | 178 result_refs.reserve(results_.size()); |
184 | 179 |
185 // Results are sorted in decreasing order so we run the loop backwards so that | 180 // Results are sorted in decreasing order so we run the loop backwards so that |
186 // the relevance increment favors the higher ranked results. | 181 // the relevance increment favors the higher ranked results. |
187 for (std::vector<history::URLResult*>::const_reverse_iterator i = | 182 for (std::vector<history::URLResult*>::const_reverse_iterator i = |
188 results_.rbegin(); i != results_.rend(); ++i) { | 183 results_.rbegin(); i != results_.rend(); ++i) { |
189 history::URLResult* result = *i; | 184 history::URLResult* result = *i; |
190 MatchReference ref(result, CalculateRelevance(*result)); | 185 MatchReference ref(result, CalculateRelevance(*result), |
186 CalculateConfidence(*result, results_)); | |
191 result_refs.push_back(ref); | 187 result_refs.push_back(ref); |
192 } | 188 } |
193 | 189 |
194 // Get the top matches and add them. | 190 // Get the top matches and add them. |
195 size_t max_for_provider = std::min(kMaxMatches, result_refs.size()); | 191 size_t max_for_provider = std::min(kMaxMatches, result_refs.size()); |
196 std::partial_sort(result_refs.begin(), result_refs.begin() + max_for_provider, | 192 std::partial_sort(result_refs.begin(), result_refs.begin() + max_for_provider, |
197 result_refs.end(), &CompareMatchRelevance); | 193 result_refs.end(), &MatchReference::CompareRelevance); |
198 matches_.clear(); | 194 matches_.clear(); |
199 for (size_t i = 0; i < max_for_provider; i++) { | 195 for (size_t i = 0; i < max_for_provider; i++) { |
200 matches_.push_back(ResultToMatch(*result_refs[i].result, | 196 AutocompleteMatch match(ResultToMatch(result_refs[i])); |
201 result_refs[i].relevance)); | 197 UMA_HISTOGRAM_COUNTS_100("Autocomplete.Confidence_HistoryContents", |
198 match.confidence * 100); | |
199 matches_.push_back(match); | |
202 } | 200 } |
mrossetti
2011/08/09 23:40:43
Perhaps calculate sum of scores here.
| |
203 } | 201 } |
204 | 202 |
205 // TODO(mrossetti): Remove MatchInTitle once body_only_ becomes permanent. | 203 // TODO(mrossetti): Remove MatchInTitle once body_only_ becomes permanent. |
206 bool HistoryContentsProvider::MatchInTitle(const history::URLResult& result) { | 204 bool HistoryContentsProvider::MatchInTitle(const history::URLResult& result) { |
207 return !body_only_ && !result.title_match_positions().empty(); | 205 return !body_only_ && !result.title_match_positions().empty(); |
208 } | 206 } |
209 | 207 |
210 AutocompleteMatch HistoryContentsProvider::ResultToMatch( | 208 AutocompleteMatch HistoryContentsProvider::ResultToMatch( |
211 const history::URLResult& result, | 209 const MatchReference& match_reference) { |
212 int score) { | 210 const history::URLResult& result = *match_reference.result; |
213 AutocompleteMatch match(this, score, true, MatchInTitle(result) ? | 211 AutocompleteMatch match(this, match_reference.relevance, |
214 AutocompleteMatch::HISTORY_TITLE : AutocompleteMatch::HISTORY_BODY); | 212 match_reference.confidence, true, MatchInTitle(result) ? |
213 AutocompleteMatch::HISTORY_TITLE : AutocompleteMatch::HISTORY_BODY); | |
215 match.contents = StringForURLDisplay(result.url(), true, trim_http_); | 214 match.contents = StringForURLDisplay(result.url(), true, trim_http_); |
216 match.fill_into_edit = | 215 match.fill_into_edit = |
217 AutocompleteInput::FormattedStringWithEquivalentMeaning(result.url(), | 216 AutocompleteInput::FormattedStringWithEquivalentMeaning(result.url(), |
218 match.contents); | 217 match.contents); |
219 match.destination_url = result.url(); | 218 match.destination_url = result.url(); |
220 match.contents_class.push_back( | 219 match.contents_class.push_back( |
221 ACMatchClassification(0, ACMatchClassification::URL)); | 220 ACMatchClassification(0, ACMatchClassification::URL)); |
222 match.description = result.title(); | 221 match.description = result.title(); |
223 match.starred = | 222 match.starred = |
224 (profile_->GetBookmarkModel() && | 223 (profile_->GetBookmarkModel() && |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
256 int HistoryContentsProvider::CalculateRelevance( | 255 int HistoryContentsProvider::CalculateRelevance( |
257 const history::URLResult& result) { | 256 const history::URLResult& result) { |
258 const bool in_title = MatchInTitle(result); | 257 const bool in_title = MatchInTitle(result); |
259 if (!profile_->GetBookmarkModel() || | 258 if (!profile_->GetBookmarkModel() || |
260 !profile_->GetBookmarkModel()->IsBookmarked(result.url())) | 259 !profile_->GetBookmarkModel()->IsBookmarked(result.url())) |
261 return in_title ? (700 + title_count_++) : (500 + contents_count_++); | 260 return in_title ? (700 + title_count_++) : (500 + contents_count_++); |
262 return in_title ? | 261 return in_title ? |
263 (1000 + star_title_count_++) : (550 + star_contents_count_++); | 262 (1000 + star_title_count_++) : (550 + star_contents_count_++); |
264 } | 263 } |
265 | 264 |
265 float HistoryContentsProvider::CalculateConfidence( | |
266 const history::URLResult& result, | |
267 const history::QueryResults& results) const { | |
268 // Calculate a score of [0, 0.9] based on typed count. | |
269 // Using typed count in place of visit count as: | |
270 // - It's a better indicator of what the user wants to open given that they | |
Peter Kasting
2011/08/09 21:52:38
Nit: To save copy+pasting, you might want to just
dominich
2011/08/10 16:10:13
I have kept these separate because the details may
| |
271 // are typing in the address bar (users tend to open certain URLs by typing | |
272 // and others by e.g. bookmarks, so visit_count is a good indicator of | |
273 // overall interest but a bad one for specifically omnibox interest). | |
274 // - Since the DB query is sorted by typed_count, the results may be | |
275 // effectively a random selection as far as visit_counts are concerned | |
276 // (meaning many high-visit_count-URLs may be present in one query and | |
277 // absent in a similar one), leading to wild swings in confidence for the | |
278 // same result across distinct queries. | |
279 float numerator = result.typed_count(); | |
280 float denominator = 0.0f; | |
281 for (std::vector<history::URLResult*>::const_iterator it = results.begin(); | |
282 it != results.end(); ++it) { | |
283 denominator += (*it)->typed_count(); | |
284 } | |
285 // It should only be equal to 0 if the result is not in the results vector. | |
286 DCHECK(denominator > 0); | |
287 float score = 0.9f * (numerator / denominator); | |
288 | |
289 // Add 0.1 if the URL is bookmarked to get a final range of [0, 1]. | |
290 if (profile_->GetBookmarkModel() && | |
291 profile_->GetBookmarkModel()->IsBookmarked(result.url())) { | |
292 score += 0.1f; | |
293 } | |
294 | |
295 return score; | |
296 } | |
297 | |
266 void HistoryContentsProvider::QueryBookmarks(const AutocompleteInput& input) { | 298 void HistoryContentsProvider::QueryBookmarks(const AutocompleteInput& input) { |
267 BookmarkModel* bookmark_model = profile_->GetBookmarkModel(); | 299 BookmarkModel* bookmark_model = profile_->GetBookmarkModel(); |
268 if (!bookmark_model) | 300 if (!bookmark_model) |
269 return; | 301 return; |
270 | 302 |
271 DCHECK(results_.empty()); | 303 DCHECK(results_.empty()); |
272 | 304 |
273 TimeTicks start_time = TimeTicks::Now(); | 305 TimeTicks start_time = TimeTicks::Now(); |
274 std::vector<bookmark_utils::TitleMatch> matches; | 306 std::vector<bookmark_utils::TitleMatch> matches; |
275 bookmark_model->GetBookmarksWithTitlesMatching(input.text(), | 307 bookmark_model->GetBookmarksWithTitlesMatching(input.text(), |
276 kMaxMatches, &matches); | 308 kMaxMatches, &matches); |
277 for (size_t i = 0; i < matches.size(); ++i) | 309 for (size_t i = 0; i < matches.size(); ++i) |
278 AddBookmarkTitleMatchToResults(matches[i]); | 310 AddBookmarkTitleMatchToResults(matches[i]); |
279 UMA_HISTOGRAM_TIMES("Omnibox.QueryBookmarksTime", | 311 UMA_HISTOGRAM_TIMES("Omnibox.QueryBookmarksTime", |
280 TimeTicks::Now() - start_time); | 312 TimeTicks::Now() - start_time); |
281 } | 313 } |
282 | 314 |
283 void HistoryContentsProvider::AddBookmarkTitleMatchToResults( | 315 void HistoryContentsProvider::AddBookmarkTitleMatchToResults( |
284 const bookmark_utils::TitleMatch& match) { | 316 const bookmark_utils::TitleMatch& match) { |
285 history::URLResult url_result(match.node->url(), match.match_positions); | 317 history::URLResult url_result(match.node->url(), match.match_positions); |
286 url_result.set_title(match.node->GetTitle()); | 318 url_result.set_title(match.node->GetTitle()); |
287 results_.AppendURLBySwapping(&url_result); | 319 results_.AppendURLBySwapping(&url_result); |
288 } | 320 } |
OLD | NEW |