Skip to content

Commit f9bcaed

Browse files
fix: Merge window and browser queries
Improves performance as events only needs to be fetched, flooded and afk-filtered once
1 parent df5a625 commit f9bcaed

File tree

2 files changed

+67
-104
lines changed

2 files changed

+67
-104
lines changed

src/queries.ts

Lines changed: 52 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -39,42 +39,6 @@ function canonicalEvents(params: DesktopQueryParams): string {
3939

4040
const default_limit = 100; // Hardcoded limit per group
4141

42-
export function windowQuery(
43-
windowbucket,
44-
afkbucket,
45-
filterAFK,
46-
classes,
47-
filterCategories: string[][]
48-
): string[] {
49-
windowbucket = windowbucket.replace('"', '\\"');
50-
afkbucket = afkbucket.replace('"', '\\"');
51-
const params: DesktopQueryParams = {
52-
bid_window: windowbucket,
53-
bid_afk: afkbucket,
54-
classes: classes,
55-
filter_afk: filterAFK,
56-
};
57-
const code =
58-
`
59-
${canonicalEvents(params)}
60-
events = categorize(events, ${JSON.stringify(params.classes)});
61-
` +
62-
(filterCategories
63-
? `events = filter_keyvals(events, "$category", ${JSON.stringify(filterCategories)});`
64-
: '') +
65-
`
66-
title_events = sort_by_duration(merge_events_by_keys(events, ["app", "title"]));
67-
app_events = sort_by_duration(merge_events_by_keys(title_events, ["app"]));
68-
cat_events = sort_by_duration(merge_events_by_keys(events, ["$category"]));
69-
70-
events = sort_by_timestamp(events);
71-
app_events = limit_events(app_events, ${default_limit});
72-
title_events = limit_events(title_events, ${default_limit});
73-
duration = sum_durations(events);
74-
RETURN = {"app_events": app_events, "title_events": title_events, "cat_events": cat_events, "duration": duration, "active_events": not_afk};`;
75-
return querystr_to_array(code);
76-
}
77-
7842
export function appQuery(
7943
appbucket: string,
8044
classes,
@@ -109,7 +73,7 @@ export function appQuery(
10973
return querystr_to_array(code);
11074
}
11175

112-
const appnames = {
76+
const browser_appnames = {
11377
chrome: [
11478
'Google-chrome',
11579
'chrome.exe',
@@ -140,7 +104,7 @@ const appnames = {
140104
// Returns a list of (browserName, bucketId) pairs for found browser buckets
141105
function browsersWithBuckets(browserbuckets: string[]): [string, string][] {
142106
const browsername_to_bucketid: [string, string | undefined][] = _.map(
143-
Object.keys(appnames),
107+
Object.keys(browser_appnames),
144108
browserName => {
145109
const bucketId = _.find(browserbuckets, bucket_id => _.includes(bucket_id, browserName));
146110
return [browserName, bucketId];
@@ -152,35 +116,28 @@ function browsersWithBuckets(browserbuckets: string[]): [string, string][] {
152116

153117
// Returns a list of active browser events (where the browser was the active window) from all browser buckets
154118
function browserEvents(params: DesktopQueryParams): string {
155-
// If multiple browser buckets were found
156-
// AFK filtered later in the process
157119
let code = `
158-
${canonicalEvents({ ...params, filter_afk: false })}
159-
window = events;
160-
events = [];
120+
browser_events = [];
161121
`;
162122

163123
_.each(browsersWithBuckets(params.bid_browsers), ([browserName, bucketId]) => {
164-
const appnames_str = JSON.stringify(appnames[browserName]);
124+
const browser_appnames_str = JSON.stringify(browser_appnames[browserName]);
165125
code += `events_${browserName} = flood(query_bucket("${bucketId}"));
166-
window_${browserName} = filter_keyvals(window, "app", ${appnames_str});
167-
${
168-
params.filter_afk
169-
? `window_${browserName} = filter_period_intersect(window_${browserName}, not_afk);`
170-
: ''
171-
}
126+
window_${browserName} = filter_keyvals(events, "app", ${browser_appnames_str});
172127
events_${browserName} = filter_period_intersect(events_${browserName}, window_${browserName});
173128
events_${browserName} = split_url_events(events_${browserName});
174-
events = sort_by_timestamp(concat(events, events_${browserName}));`;
129+
browser_events = sort_by_timestamp(concat(browser_events, events_${browserName}));`;
175130
});
176131
return code;
177132
}
178133

179-
export function browserSummaryQuery(
134+
export function fullDesktopQuery(
180135
browserbuckets: string[],
181136
windowbucket: string,
182137
afkbucket: string,
183-
filterAFK = true
138+
filterAFK = true,
139+
classes,
140+
filterCategories: string[][]
184141
): string[] {
185142
// Escape `"`
186143
browserbuckets = _.map(browserbuckets, b => b.replace('"', '\\"'));
@@ -192,21 +149,51 @@ export function browserSummaryQuery(
192149
bid_window: windowbucket,
193150
bid_afk: afkbucket,
194151
bid_browsers: browserbuckets,
195-
classes: {},
152+
classes: classes,
196153
filter_afk: filterAFK,
197154
};
198155

199156
return querystr_to_array(
200-
`${browserEvents(params)}
201-
urls = merge_events_by_keys(events, ["url"]);
202-
urls = sort_by_duration(urls);
203-
urls = limit_events(urls, ${default_limit});
204-
domains = split_url_events(events);
205-
domains = merge_events_by_keys(domains, ["$domain"]);
206-
domains = sort_by_duration(domains);
207-
domains = limit_events(domains, ${default_limit});
157+
`
158+
${canonicalEvents(params)}
159+
events = categorize(events, ${JSON.stringify(params.classes)});
160+
` +
161+
(filterCategories
162+
? `events = filter_keyvals(events, "$category", ${JSON.stringify(filterCategories)});`
163+
: '') +
164+
`
165+
title_events = sort_by_duration(merge_events_by_keys(events, ["app", "title"]));
166+
app_events = sort_by_duration(merge_events_by_keys(title_events, ["app"]));
167+
cat_events = [];
168+
cat_events = sort_by_duration(merge_events_by_keys(events, ["$category"]));
169+
170+
app_events = limit_events(app_events, ${default_limit});
171+
title_events = limit_events(title_events, ${default_limit});
208172
duration = sum_durations(events);
209-
RETURN = {"domains": domains, "urls": urls, "duration": duration};`
173+
174+
${browserEvents(params)}
175+
browser_events = split_url_events(browser_events);
176+
browser_urls = merge_events_by_keys(browser_events, ["url"]);
177+
browser_urls = sort_by_duration(browser_urls);
178+
browser_urls = limit_events(browser_urls, ${default_limit});
179+
browser_domains = merge_events_by_keys(browser_events, ["$domain"]);
180+
browser_domains = sort_by_duration(browser_domains);
181+
browser_domains = limit_events(browser_domains, ${default_limit});
182+
browser_duration = sum_durations(browser_events);
183+
184+
RETURN = {
185+
"window": {
186+
"app_events": app_events,
187+
"title_events": title_events,
188+
"cat_events": cat_events,
189+
"duration": duration
190+
},
191+
"browser": {
192+
"domains": browser_domains,
193+
"urls": browser_urls,
194+
"duration": browser_duration
195+
}
196+
};`
210197
);
211198
}
212199

@@ -234,6 +221,7 @@ export function dailyActivityQuery(afkbucket: string): string[] {
234221
return [
235222
'afkbucket = "' + afkbucket + '";',
236223
'not_afk = flood(query_bucket(afkbucket));',
224+
'not_afk = filter_keyvals(not_afk, "status", ["not-afk"]);',
237225
'not_afk = merge_events_by_keys(not_afk, ["status"]);',
238226
'RETURN = not_afk;',
239227
];
@@ -245,8 +233,7 @@ export function dailyActivityQueryAndroid(androidbucket: string): string[] {
245233
}
246234

247235
export default {
248-
windowQuery,
249-
browserSummaryQuery,
236+
fullDesktopQuery,
250237
appQuery,
251238
dailyActivityQuery,
252239
dailyActivityQueryAndroid,

src/store/modules/activity.ts

Lines changed: 15 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ const _state = {
6363
active: {
6464
available: false,
6565
duration: 0,
66-
events: [],
6766
history: {},
6867
},
6968

@@ -133,22 +132,14 @@ const actions = {
133132
await dispatch('set_available', query_options);
134133

135134
if (state.window.available) {
136-
await dispatch('query_window', query_options);
135+
await dispatch('query_desktop_full', query_options);
137136
} else if (state.android.available) {
138137
await dispatch('query_android', query_options);
139138
} else {
140139
console.log(
141140
'Cannot query windows as we are missing either an afk/window bucket pair or an android bucket'
142141
);
143142
await dispatch('query_window_empty', query_options);
144-
}
145-
146-
if (state.browser.available) {
147-
await dispatch('query_browser', query_options);
148-
} else {
149-
console.log(
150-
'Cannot call query_browser as we are missing either an afk, window or browser bucket'
151-
);
152143
await dispatch('query_browser_empty', query_options);
153144
}
154145

@@ -174,22 +165,6 @@ const actions = {
174165
}
175166
},
176167

177-
async query_window({ state, commit }, { timeperiod, filterAFK, filterCategories }: QueryOptions) {
178-
const periods = [timeperiodToStr(timeperiod)];
179-
const start = moment();
180-
const classes = loadClassesForQuery();
181-
const q = queries.windowQuery(
182-
state.buckets.window[0],
183-
state.buckets.afk[0],
184-
filterAFK,
185-
classes,
186-
filterCategories
187-
);
188-
const data = await this._vm.$aw.query(periods, q);
189-
commit('query_window_completed', data[0]);
190-
console.info(`Completed window query in ${moment().diff(start)}ms`);
191-
},
192-
193168
async query_android({ state, commit }, { timeperiod, filterCategories }: QueryOptions) {
194169
const periods = [timeperiodToStr(timeperiod)];
195170
const classes = loadClassesForQuery();
@@ -204,21 +179,27 @@ const actions = {
204179
title_events: [],
205180
cat_events: [],
206181
duration: 0,
207-
active_events: [],
208182
};
209183
commit('query_window_completed', data);
210184
},
211185

212-
async query_browser({ state, commit }, { timeperiod, filterAFK }: QueryOptions) {
186+
async query_desktop_full(
187+
{ state, commit },
188+
{ timeperiod, filterCategories, filterAFK }: QueryOptions)
189+
{
213190
const periods = [timeperiodToStr(timeperiod)];
214-
const q = queries.browserSummaryQuery(
191+
const classes = loadClassesForQuery();
192+
const q = queries.fullDesktopQuery(
215193
state.buckets.browser,
216194
state.buckets.window[0],
217195
state.buckets.afk[0],
218-
filterAFK
196+
filterAFK,
197+
classes,
198+
filterCategories
219199
);
220200
const data = await this._vm.$aw.query(periods, q);
221-
commit('query_browser_completed', data[0]);
201+
commit('query_browser_completed', data[0].browser);
202+
commit('query_window_completed', data[0].window);
222203
},
223204

224205
async query_browser_empty({ commit }) {
@@ -430,9 +411,6 @@ const actions = {
430411
app_events,
431412
title_events,
432413
cat_events,
433-
active_events: [
434-
{ timestamp: new Date().toISOString(), duration: 1.5 * 60 * 60, data: { afk: 'not-afk' } },
435-
],
436414
});
437415

438416
commit('browser_buckets', ['aw-watcher-firefox']);
@@ -492,7 +470,6 @@ const mutations = {
492470
state.category.top = null;
493471

494472
state.active.duration = null;
495-
state.active.events = null;
496473

497474
// Ensures that active history isn't being fully reloaded on every date change
498475
// (see caching done in query_active_history and query_active_history_android)
@@ -516,13 +493,12 @@ const mutations = {
516493
state.window.top_titles = data['title_events'];
517494
state.category.top = data['cat_events'];
518495
state.active.duration = data['duration'];
519-
state.active.events = data['active_events'];
520496
},
521497

522498
query_browser_completed(state, data) {
523-
state.browser.top_domains = data['domains'];
524-
state.browser.top_urls = data['urls'];
525-
state.browser.duration = data['duration'];
499+
state.browser.top_domains = data.domains;
500+
state.browser.top_urls = data.urls;
501+
state.browser.duration = data.duration;
526502

527503
// FIXME: This one might take up a lot of size in the request, move it to a seperate request
528504
// (or remove entirely, since we have the other timeline now)

0 commit comments

Comments
 (0)