Merge lp:~gary-wzl77/scope-aggregator/fix_1490828 into lp:scope-aggregator
- fix_1490828
- Merge into vivid-trunk
Status: | Merged |
---|---|
Approved by: | Kyle Nitzsche |
Approved revision: | 150 |
Merged at revision: | 149 |
Proposed branch: | lp:~gary-wzl77/scope-aggregator/fix_1490828 |
Merge into: | lp:scope-aggregator |
Diff against target: |
292 lines (+142/-52) 4 files modified
README.md (+27/-0) include/query.h (+2/-0) src/query.cpp (+89/-51) src/utils.cpp (+24/-1) |
To merge this branch: | bzr merge lp:~gary-wzl77/scope-aggregator/fix_1490828 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Kyle Nitzsche (community) | Approve | ||
Review via email: mp+269709@code.launchpad.net |
Commit message
load correct keyword for a scope with multiple keywords when dept changed.
Add link_to_child in keyword struct to make it possible to navigateto child scope.
Description of the change
load correct keyword for a scope with multiple keywords when dept changed.
Add link_to_child in keyword struct to make it possible to navigateto child scope.
Gary.Wang (gary-wzl77) wrote : | # |
1.Indeed, it might cause unnecessary code execution, which is sth I didn't take into account. I've re-submitted and move code[30-41] below scope registry list, since that's more reasonable.
2.Yes, I'm sure. To take a trivial instance, for all child scopes in bollywood aggregator, one of the requirement is there is a need for them to linked to corresponding child scope by clicking the header(child scope name). And as you said, not every child scope should obviously be linked to a given keyword aggregation. In such a case, I think developer could isolate the special one by declaring another keyword or scope json object since link_to_child property in keyword object is applied for all child scopes.
Gary.Wang (gary-wzl77) wrote : | # |
Regarding question2, There is one issue related on this
e.g. amazon scope has keyword "books", if we simply use keyword as following
...
{
{
}
}
...
There're some results returned from amazon scope, but these results items have nth to do with "books" keywords. Reason for this is developer didn't handle "books" keyword in source code although scope supports the keyword.
So if we isolate amazon by declaring scope json object with default_
{
{
}
},
{
{
}
}
We can see there two amazon scope exists since keyword object is applied for all child scopes.First one is explicit declared amazon scope, second one is amazon scope with "books" keywords. That looks bad.
So two ways to fix the duplicated issue.
1. Fix in child scope(amazon)
2. Fix in scope aggregator with adding new property exclude_scopes
e.g.
{
{
}
},
{
{
]
}
}
So in this way, we keep the first one and second one will be ignored since it's excluded in keyword scope list. I've added this new property in scope agg and have a quick testing, It works fine.
If we own source code, I prefer 1st option.
In the future if scopes which we don't own source code have the same issue that amazon has. I think the second one is better one. At the same time, I think it's also applied for link_to_child property. If there is no need for one certain scope to navigate to child scope, we can write it as following
e.g
{
{
}
},
{
{
]
}
}
I'd like to hear you option on this and will submit my MR if this suggestion looks good to you.
Thanks
Kyle Nitzsche (knitzsche) wrote : | # |
Hi Gary,
We already have "link_to_
So, how about if we add "link_to_
This way the keyword can link to a specific child *with* a default query string.
Note that "link_to_
Gary.Wang (gary-wzl77) wrote : | # |
Personally, I trend to prefer to add "exclude_scopes" property in keyword object, reasons as following:
1. if add "link_to_
let me take an instance I meet during my development
e.g. there're 5 book child scopes [amazon, ebay, douban, open library, viva reader], all of them supports "books" keyword
{
{
}
}
* In this case, amazon, ebay, open library works fine, but no results returned for douban, viva reader since both two Chinese child scope only support Chinese querying. However both child scope can give correct results when loading default department without query string just as open as usual.
2. The main point for adding "exclude_scopes" is we can get rid of one or *more* scopes in keyword object and drop them or isolate them to display in another ways[category, scope] to avoid duplicated display issue for one or *more* scope in scope aggregator.
Kyle Nitzsche (knitzsche) wrote : | # |
Hi Gary,
Regarding the proposal for keyword category link_to_
Link_to_
{
{
}
}
Because this approach expands the use of an existing feature (link_to_
On the topic of exclude_scopes. in your opinion, is this needed if we use my proposal (or is it a choice between the two approaches).
Gary.Wang (gary-wzl77) wrote : | # |
I think your approach does work for the case with some limitation as following
1.scopes: [amazon, ebay, open_library, douban, viva] ----> all of them support "books" keyword
2.all of them are supposed to link to child scopes.
limitation:
1.amazon gives us items which completely unrelated to "books" keyword since developer didn't deal with "books" keywords in source code.
2.english query string (default_
Could you please write your json code based on my requirement as above ?
Thanks.
Kyle Nitzsche (knitzsche) wrote : | # |
Hi Gary,
I did not understand that you want *every* keyword child scope to have a link to child.
So, I think we have discussed this enough. :)
You understand my preference to reuse and expand existing features and json keys where possible.
But if that does not meet the particular requirements, then please go ahead and complete the implementation as you have described, including the exclude_scopes key and I will approve after normal review.
cheers,
Kyle
Gary.Wang (gary-wzl77) wrote : | # |
Basically, at least for all the scope aggregator I implement "link to child" for every scope is required.
I've submitted latest MR.
Please review.
Kyle Nitzsche (knitzsche) wrote : | # |
Looks good, thanks.
Preview Diff
1 | === modified file 'README.md' |
2 | --- README.md 2015-07-15 03:34:23 +0000 |
3 | +++ README.md 2015-09-14 03:04:52 +0000 |
4 | @@ -759,3 +759,30 @@ |
5 | } |
6 | } |
7 | ] |
8 | + |
9 | + |
10 | +#### `exclude_scopes` key (optional) |
11 | + |
12 | +Value: json list of objects. |
13 | + |
14 | +Suppose you want some scopes which supports one certain keywords not to display results, you can specify scope id in the exclude_scopes and scope aggregator will not displays results of specified scopes. |
15 | + |
16 | +Note:This key is only supposed to be declared in a `keywords` json object, which doesn't not use a shared category. |
17 | +e.g. amazon supports 'books' keyword, but in most cases it returns something unrelated to 'books' keyword. we can get rid of its results in the way as following. |
18 | + "order": |
19 | + [ |
20 | + { |
21 | + "keyword": |
22 | + { |
23 | + "keyword": "books", |
24 | + "link_to_child" : "true", |
25 | + "exclude_scopes" :[ |
26 | + { |
27 | + "id": "com.canonical.scopes.amazon" |
28 | + } |
29 | + ] |
30 | + } |
31 | + } |
32 | + ] |
33 | + |
34 | + |
35 | |
36 | === modified file 'include/query.h' |
37 | --- include/query.h 2015-08-04 19:12:04 +0000 |
38 | +++ include/query.h 2015-09-14 03:04:52 +0000 |
39 | @@ -153,6 +153,8 @@ |
40 | int cardinality = -1; |
41 | std::string dept_id; |
42 | std::string dept_title_msgid; |
43 | + bool link_to_child = false; |
44 | + std::vector<std::string> exclude_scopes; // id of exclude scopes |
45 | }; |
46 | std::vector<std::shared_ptr<keyword>> keywords;// pulled from child_sccopes.json |
47 | std::map<std::string, std::shared_ptr<keyword>> id_keyword_map;//keyword id (the keyword string) to keyword instance |
48 | |
49 | === modified file 'src/query.cpp' |
50 | --- src/query.cpp 2015-09-04 20:12:11 +0000 |
51 | +++ src/query.cpp 2015-09-14 03:04:52 +0000 |
52 | @@ -289,27 +289,27 @@ |
53 | us::CannedQuery canned_query = query(); |
54 | std::string dept_id = canned_query.department_id(); |
55 | |
56 | + // skip to next if scope is not registered in the system |
57 | + auto reg_scopes = registry_->list(); |
58 | + us::MetadataMap::const_iterator scope_it; |
59 | + scope_it = reg_scopes.find(localId_id_m[local_id]); |
60 | + if (scope_it == reg_scopes.end()) { |
61 | + qWarning () << QString("%1: scope is NOT REGISTERED, skipping: %2").arg(qstr(SCOPE_ID), qstr(localId_id_m[local_id])); |
62 | + continue; |
63 | + } |
64 | + |
65 | //TODO: add to docs note that when declaring a scope more than once, all must be in different depts |
66 | if (using_departments) |
67 | { |
68 | if (dept_id == "") //is root dept |
69 | { |
70 | if(scope->department() != dept_id_of_root) |
71 | - continue; |
72 | + continue; |
73 | } |
74 | else if(scope->department() != query().department_id()) |
75 | continue; |
76 | } |
77 | - |
78 | - // skip to next if scope is not registered in the system |
79 | - auto reg_scopes = registry_->list(); |
80 | - us::MetadataMap::const_iterator scope_it; |
81 | - scope_it = reg_scopes.find(localId_id_m[local_id]); |
82 | - if (scope_it == reg_scopes.end()) { |
83 | - qWarning () << QString("%1: scope is NOT REGISTERED, skipping: %2").arg(qstr(SCOPE_ID), qstr(localId_id_m[local_id])); |
84 | - continue; |
85 | - } |
86 | - |
87 | + |
88 | // if scope is not in the currently enabled list, skip it |
89 | bool found_as_enabled = false; |
90 | for (auto cs : current_child_scopes)//FQ ids |
91 | @@ -322,12 +322,33 @@ |
92 | } |
93 | } |
94 | } |
95 | + |
96 | if (!found_as_enabled) |
97 | { |
98 | qWarning () << QString("%1: scope is NOT ENABLED, skipping: %2").arg(qstr(SCOPE_ID), qstr(localId_id_m[local_id])); |
99 | continue; |
100 | } |
101 | |
102 | + // if scope is in exclude scopes list, skip it |
103 | + bool found_as_exclude = false; |
104 | + for (auto kw : keywords) |
105 | + { |
106 | + if (kw->id == scope->keyword()) { |
107 | + auto iter = std::find(kw->exclude_scopes.begin(), kw->exclude_scopes.end(), scope->id()); |
108 | + if (iter != kw->exclude_scopes.end()) |
109 | + { |
110 | + found_as_exclude = true; |
111 | + qWarning () << QString("==== FOUND AS EXCLUDE: %1: scope is in exclude scopes of keyword: %2") |
112 | + .arg(qstr(scope->id()), qstr(scope->keyword())); |
113 | + } |
114 | + } |
115 | + } |
116 | + |
117 | + if (found_as_exclude) { |
118 | + continue; |
119 | + } |
120 | + |
121 | + |
122 | if (query_string.empty() && scope->only_in_search() == true) |
123 | { |
124 | continue; |
125 | @@ -612,13 +633,33 @@ |
126 | } |
127 | if (!upstream_reply->lookup_category(cat_id)) |
128 | { |
129 | - scope->set_category(upstream_reply->register_category |
130 | - ( |
131 | - cat_id, |
132 | - cat_title, |
133 | - "", |
134 | - us::CategoryRenderer(rdr) |
135 | - )); |
136 | + if (scope->category_link_to_child()) |
137 | + { |
138 | + scope->set_category |
139 | + ( |
140 | + upstream_reply->register_category |
141 | + ( |
142 | + cat_id, |
143 | + cat_title, |
144 | + "", |
145 | + us::CannedQuery(scope->id(), query_string, scope->child_department()), |
146 | + us::CategoryRenderer(rdr) |
147 | + ) |
148 | + ); |
149 | + } |
150 | + else |
151 | + { |
152 | + scope->set_category |
153 | + ( |
154 | + upstream_reply->register_category |
155 | + ( |
156 | + cat_id, |
157 | + cat_title, |
158 | + "", |
159 | + us::CategoryRenderer(rdr) |
160 | + ) |
161 | + ); |
162 | + } |
163 | } |
164 | } |
165 | res.set_category(scope->category()); |
166 | @@ -1049,39 +1090,36 @@ |
167 | { |
168 | if (!rdr.empty()) // should not ever be empty! |
169 | { |
170 | - if (scope->category_link_to_child()) |
171 | - { |
172 | - if (!upstream_reply->lookup_category(cat_id)) |
173 | - { |
174 | - scope->set_category |
175 | - ( |
176 | - upstream_reply->register_category |
177 | - ( |
178 | - cat_id, |
179 | - cat_title, |
180 | - "", |
181 | - us::CannedQuery(scope->id(), query_string, scope->child_department()), |
182 | - us::CategoryRenderer(rdr) |
183 | - ) |
184 | - ); |
185 | - } |
186 | - } |
187 | - else |
188 | - { |
189 | - if (!upstream_reply->lookup_category(cat_id)) |
190 | - { |
191 | - scope->set_category |
192 | - ( |
193 | - upstream_reply->register_category |
194 | - ( |
195 | - cat_id, |
196 | - cat_title, |
197 | - "", |
198 | - us::CategoryRenderer(rdr) |
199 | - ) |
200 | - ); |
201 | - } |
202 | - } |
203 | + if (!upstream_reply->lookup_category(cat_id)) |
204 | + { |
205 | + if (scope->category_link_to_child()) |
206 | + { |
207 | + scope->set_category |
208 | + ( |
209 | + upstream_reply->register_category |
210 | + ( |
211 | + cat_id, |
212 | + cat_title, |
213 | + "", |
214 | + us::CannedQuery(scope->id(), query_string, scope->child_department()), |
215 | + us::CategoryRenderer(rdr) |
216 | + ) |
217 | + ); |
218 | + } |
219 | + else |
220 | + { |
221 | + scope->set_category |
222 | + ( |
223 | + upstream_reply->register_category |
224 | + ( |
225 | + cat_id, |
226 | + cat_title, |
227 | + "", |
228 | + us::CategoryRenderer(rdr) |
229 | + ) |
230 | + ); |
231 | + } |
232 | + } |
233 | } |
234 | else |
235 | qWarning() << QString("Warning: Scope %1 renderer is empty.").arg(qstr(scope->id())); |
236 | |
237 | === modified file 'src/utils.cpp' |
238 | --- src/utils.cpp 2015-08-04 19:12:04 +0000 |
239 | +++ src/utils.cpp 2015-09-14 03:04:52 +0000 |
240 | @@ -648,6 +648,23 @@ |
241 | QJsonDocument rdr_d(renderer_o); |
242 | keyword_catname_search_renderer[category] = sstr(rdr_d.toJson()); |
243 | } |
244 | + if (keyword_o.contains("link_to_child")) |
245 | + { |
246 | + if (keyword_o["link_to_child"].toString() == "true") |
247 | + keyword_.link_to_child = true; |
248 | + } |
249 | + if (keyword_o.contains("exclude_scopes")) |
250 | + { |
251 | + QJsonArray scope_a = keyword_o["exclude_scopes"].toArray(); |
252 | + |
253 | + for (const auto item : scope_a) |
254 | + { |
255 | + QJsonObject scope_o = item.toObject(); |
256 | + std::string id = scope_o["id"].toString().toStdString(); |
257 | + keyword_.exclude_scopes.emplace_back(id); |
258 | + } |
259 | + } |
260 | + |
261 | std::shared_ptr<keyword> kw_ptr = std::make_shared<keyword>(keyword_); |
262 | keywords.emplace_back(kw_ptr); |
263 | id_keyword_map[keyword_id] = kw_ptr; |
264 | @@ -812,7 +829,6 @@ |
265 | AggChildScope keych(keyword_child.id); |
266 | QString time_str = QDateTime::currentDateTimeUtc().toString(); |
267 | keych.set_local_id(keyword_child.id + time_str.toStdString()); |
268 | - keych.set_category_link_to_child(true); |
269 | keych.set_keyword_scope(true); |
270 | dept d; |
271 | d.id = keyword_child.id; |
272 | @@ -837,6 +853,7 @@ |
273 | d.keyword = kw; |
274 | keych.set_department(kw); |
275 | keych.set_keyword(kw); |
276 | + keych.set_category_link_to_child(id_keyword_map[kw]->link_to_child); |
277 | qWarning() << "==== ID KW 1: " << qstr(keych.keyword()); |
278 | |
279 | bool a_dup = false; |
280 | @@ -844,6 +861,12 @@ |
281 | if (using_departments) |
282 | { |
283 | std::string curr_dept_id = query().department_id(); |
284 | + |
285 | + //make sure we load correct dept id if we specify department property in keyword object |
286 | + if (!curr_dept_id.empty() && keyword_deptId[kw] != curr_dept_id) { |
287 | + continue; |
288 | + } |
289 | + |
290 | for (std::shared_ptr<child_scope> cs : child_scopes) |
291 | { |
292 | if (keyword_child.id != cs->id) |
Gary: Nice work.
A couple comments:
1) lines 30-41: This removes the code in handle_ child_results( ) that skips a scope when it is not in the current department. I understand you added code to do the same thing for *keyword* scopes (lines 193 to 198). Also, the main lambda function that handles each child result *does* filter out results when they are not in the current department in all cases. So even with your MR the user should not see the scope if it is in the wrong department. But, there is no need to process results for scopes that are not in the current department with the lambda function, so the approach of removing lines 30-41 seems to result in unnecessary code execution (unless I have misunderstood something :) So it seems to me that lines 30-41 should not be removed. Thoughts?
2) You have added support for a declared "keyword" to have a link_to_child. I did not add this previously because a "keyword" by definition may include any number of child scopes (including zero). There is no guarantee that any particular child is installed. And there is no single child that should obviously be linked to given the dynamic and unpredictable nature or keyword aggregation. Are you sure we have a use case for this?