Merge lp:~jamesh/unity-scope-scopes/remove-duplicate-results into lp:unity-scope-scopes

Proposed by James Henstridge
Status: Merged
Approved by: Michal Hruby
Approved revision: 36
Merged at revision: 30
Proposed branch: lp:~jamesh/unity-scope-scopes/remove-duplicate-results
Merge into: lp:unity-scope-scopes
Diff against target: 241 lines (+106/-47)
2 files modified
src/scopes-scope.cpp (+102/-46)
src/scopes-scope.h (+4/-1)
To merge this branch: bzr merge lp:~jamesh/unity-scope-scopes/remove-duplicate-results
Reviewer Review Type Date Requested Status
Michal Hruby (community) Approve
Review via email: mp+213515@code.launchpad.net

Commit message

Fix result de-duplication in the slow path, and update the presentation of results a bit to match the design better.

Description of the change

The scopes scope was not correctly removing duplicate results in the slow path for pushing results. This branch fixes this.

In addition, it makes a few other changes:

1. Don't query for online results when surfacing.

2. When presenting search results, use a different rendering template and present results under a single category.

3. Use the actual author metadata in results.

4. Copy over the department value from online results and use it when activating the result.

To post a comment you must log in.
Revision history for this message
Michal Hruby (mhr3) wrote :

The de-duplication works fine now and search results look more like in the design.

Do we plan to add also the ability to list the same scope multiple times (with different departments)? Is that going to be in this branch, or should we just land this and fix that in another one?

review: Needs Information
34. By James Henstridge

Handle the case where the online scope provides multiple recommendations
for a particular scope.

Revision history for this message
James Henstridge (jamesh) wrote :

Okay. It now presents multiple recommendations for the same scope.

It's not perfect though: if the online scope is slow in returning its results and we match a particular scope locally, we won't provide multiple results for it when we do the second query to the online scope.

35. By James Henstridge

Remove unneeded include.

Revision history for this message
Michal Hruby (mhr3) wrote :

64 + // don't display ourselves
65 + if (item.scope_id() == "scopes") continue;

Could we drop this? Now that we have the invisible flag it shouldn't be needed.

36. By James Henstridge

There is no need to special case removal of the scopes scope from
results, since it is marked invisible.

Revision history for this message
Michal Hruby (mhr3) wrote :

Thanks, +1.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/scopes-scope.cpp'
2--- src/scopes-scope.cpp 2014-03-19 13:57:54 +0000
3+++ src/scopes-scope.cpp 2014-04-01 13:33:22 +0000
4@@ -54,6 +54,21 @@
5 }
6 )";
7 // unconfuse emacs: "
8+static const char SEARCH_CATEGORY_DEFINITION[] = R"(
9+{
10+ "schema-version": 1,
11+ "template": {
12+ "category-layout": "grid",
13+ "card-size": "small",
14+ "card-layout": "horizontal"
15+ },
16+ "components": {
17+ "title": "title",
18+ "subtitle": "author",
19+ "mascot": "icon"
20+ }
21+}
22+)";
23
24 int ScopesScope::start(std::string const&, RegistryProxy const &registry) {
25 this->registry = registry;
26@@ -176,6 +191,14 @@
27 }
28
29 void ScopesQuery::run(SearchReplyProxy const &reply) {
30+ if (query.query_string().empty()) {
31+ surfacing_query(reply);
32+ } else {
33+ search_query(reply);
34+ }
35+}
36+
37+void ScopesQuery::surfacing_query(SearchReplyProxy const &reply) {
38 CategoryRenderer renderer(SCOPES_CATEGORY_DEFINITION);
39 Category::SCPtr categories[N_CATEGORIES];
40 categories[CAT_FEATURED] = reply->register_category(
41@@ -185,12 +208,41 @@
42 categories[CAT_OTHER] = reply->register_category(
43 "scopes", "Other", "", renderer);
44
45+ MetadataMap all_scopes = scope.registry->list();
46+ std::vector<ScopeMetadata> scopes;
47+ for (const auto &pair : all_scopes) {
48+ const auto &item = pair.second;
49+ if (item.invisible())
50+ continue;
51+ scopes.push_back(item);
52+ }
53+ std::sort(scopes.begin(), scopes.end(), compareMetadata);
54+
55+ for (const auto &item : scopes) {
56+ // TODO: categorisation of scopes should come from the
57+ // metadata rather than being hard coded.
58+ Category::SCPtr category;
59+ try {
60+ ScopeCategory cat_id = category_mapping.at(item.scope_id());
61+ category = categories[cat_id];
62+ } catch (std::out_of_range &e) {
63+ category = categories[CAT_OTHER];
64+ }
65+ push_scope_result(reply, item, category, nullptr);
66+ }
67+}
68+
69+void ScopesQuery::search_query(SearchReplyProxy const &reply) {
70+ CategoryRenderer renderer(SEARCH_CATEGORY_DEFINITION);
71+ Category::SCPtr category = reply->register_category(
72+ "scopes", "Scopes", "", renderer);
73+
74 std::string term = lowercase(query.query_string());
75
76 std::shared_ptr<ResultCollector> online_query;
77- std::map<std::string, std::string> recommended_scopes;
78+ std::map<std::string, std::vector<Result>> recommended_scopes;
79 std::list<CategorisedResult> online_results;
80-
81+
82 if (scope.online_scope && !query.query_string().empty()) {
83 online_query.reset(new ResultCollector);
84 try {
85@@ -209,11 +261,7 @@
86 if (result.category()->id() == "recommendations") {
87 if (result.contains("scope_id")) {
88 auto scope_id = result["scope_id"].get_string();
89- std::string search_string;
90- if (result.contains("search_string")) {
91- search_string = result["search_string"].get_string();
92- }
93- recommended_scopes[scope_id] = search_string;
94+ recommended_scopes[scope_id].push_back(result);
95 }
96 } else {
97 if (!reply->lookup_category(result.category()->id())) {
98@@ -252,19 +300,15 @@
99 // don't display ourselves
100 if (item.scope_id() == "scopes") continue;
101
102- // TODO: categorisation of scopes should come from the
103- // metadata rather than being hard coded.
104- Category::SCPtr category;
105- try {
106- ScopeCategory cat_id = category_mapping.at(item.scope_id());
107- category = categories[cat_id];
108- } catch (std::out_of_range &e) {
109- category = categories[CAT_OTHER];
110- }
111+ pushed_scope_ids.insert(item.scope_id());
112 auto it = recommended_scopes.find(item.scope_id());
113- pushed_scope_ids.insert(item.scope_id());
114- std::string search_string = it != recommended_scopes.end() ? it->second : "";
115- push_scope_result(reply, item, category, search_string);
116+ if (it == recommended_scopes.end()) {
117+ push_scope_result(reply, item, category, nullptr);
118+ } else {
119+ for (auto &online_result : it->second) {
120+ push_scope_result(reply, item, category, &online_result);
121+ }
122+ }
123 }
124
125 // second round, wait for the server results without any time limits
126@@ -278,17 +322,14 @@
127 auto scope_id = result["scope_id"].get_string();
128 if (pushed_scope_ids.find(scope_id) != pushed_scope_ids.end())
129 continue;
130- std::string search_string;
131- if (result.contains("search_string")) {
132- search_string = result["search_string"].get_string();
133- }
134- recommended_scopes[scope_id] = search_string;
135- }
136- }
137- if (!reply->lookup_category(result.category()->id())) {
138- reply->register_category(result.category());
139- }
140- reply->push(result);
141+ recommended_scopes[scope_id].push_back(result);
142+ }
143+ } else {
144+ if (!reply->lookup_category(result.category()->id())) {
145+ reply->register_category(result.category());
146+ }
147+ reply->push(result);
148+ }
149 }
150
151 for (auto const& pair : recommended_scopes) {
152@@ -298,22 +339,15 @@
153
154 auto const& item = meta_it->second;
155 // push more results
156- Category::SCPtr category;
157- try {
158- ScopeCategory cat_id = category_mapping.at(item.scope_id());
159- category = categories[cat_id];
160- } catch (std::out_of_range &e) {
161- category = categories[CAT_OTHER];
162- }
163- auto it = recommended_scopes.find(item.scope_id());
164 pushed_scope_ids.insert(item.scope_id());
165- std::string search_string = it != recommended_scopes.end() ? it->second : "";
166- push_scope_result(reply, item, category, search_string);
167+ for (auto &online_result : pair.second) {
168+ push_scope_result(reply, item, category, &online_result);
169+ }
170 }
171 }
172 }
173
174-void ScopesQuery::push_scope_result(SearchReplyProxy const &reply, ScopeMetadata const& item, Category::SCPtr const& category, std::string const& search_string)
175+void ScopesQuery::push_scope_result(SearchReplyProxy const &reply, ScopeMetadata const& item, Category::SCPtr const& category, Result const *online_result)
176 {
177 std::string uri = "scope://" + item.scope_id();
178 CategorisedResult result(category);
179@@ -330,11 +364,23 @@
180 } catch (NotFoundException &e) {
181 }
182 result.set_dnd_uri(uri);
183- result["scope_name"] = item.scope_id();
184- // FIXME: this should be provided by the scope metadata
185- result["author"] = "Canonical Ltd";
186+ result["scope_id"] = item.scope_id();
187+ result["author"] = item.author();
188 result["description"] = item.description();
189- result["search_string"] = search_string;
190+ if (online_result != nullptr) {
191+ if (online_result->contains("subtitle")) {
192+ const auto subtitle = (*online_result)["subtitle"].get_string();
193+ if (!subtitle.empty()) {
194+ result["author"] = (*online_result)["subtitle"];
195+ }
196+ }
197+ if (online_result->contains("search_string")) {
198+ result["search_string"] = (*online_result)["search_string"];
199+ }
200+ if (online_result->contains("scope_department")) {
201+ result["scope_department"] = (*online_result)["scope_department"];
202+ }
203+ }
204 std::string icon;
205 try {
206 icon = item.icon();
207@@ -400,7 +446,17 @@
208 }
209
210 ActivationResponse ScopesActivation::activate() {
211- CannedQuery query(result["scope_name"].get_string(), result["search_string"].get_string(), "");
212+ std::string scope_id = result["scope_id"].get_string();
213+ std::string search_string;
214+ std::string department_id;
215+ if (result.contains("search_string")) {
216+ search_string = result["search_string"].get_string();
217+ }
218+ if (result.contains("scope_department")) {
219+ department_id = result["scope_department"].get_string();
220+ }
221+
222+ CannedQuery query(scope_id, search_string, department_id);
223 return ActivationResponse(query);
224 }
225
226
227=== modified file 'src/scopes-scope.h'
228--- src/scopes-scope.h 2014-03-05 10:13:09 +0000
229+++ src/scopes-scope.h 2014-04-01 13:33:22 +0000
230@@ -51,7 +51,10 @@
231 virtual void run(unity::scopes::SearchReplyProxy const&reply) override;
232
233 private:
234- void push_scope_result(unity::scopes::SearchReplyProxy const &reply, unity::scopes::ScopeMetadata const& item, unity::scopes::Category::SCPtr const& category, std::string const& search_string);
235+ void surfacing_query(unity::scopes::SearchReplyProxy const &reply);
236+ void search_query(unity::scopes::SearchReplyProxy const &reply);
237+
238+ void push_scope_result(unity::scopes::SearchReplyProxy const &reply, unity::scopes::ScopeMetadata const& item, unity::scopes::Category::SCPtr const& category, unity::scopes::Result const *online_result);
239
240 const ScopesScope &scope;
241 const unity::scopes::CannedQuery query;

Subscribers

People subscribed via source and target branches

to all changes: