forked from PinSpace-Org/GistPin
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch-analytics.ts
More file actions
59 lines (53 loc) 路 1.86 KB
/
Copy pathsearch-analytics.ts
File metadata and controls
59 lines (53 loc) 路 1.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
export interface SearchQuery {
term: string;
timestamp: Date;
userId?: string;
filters?: Record<string, string>;
resultCount: number;
clickCount: number;
}
export interface SearchAggregation {
term: string;
totalSearches: number;
uniqueUsers: number;
avgResultCount: number;
clickThroughRate: number;
lastSearched: Date;
}
export function aggregateSearches(queries: SearchQuery[]): SearchAggregation[] {
const grouped = new Map<string, SearchQuery[]>();
for (const q of queries) {
const key = q.term.toLowerCase();
if (!grouped.has(key)) grouped.set(key, []);
grouped.get(key)!.push(q);
}
return Array.from(grouped.entries()).map(([term, entries]) => {
const uniqueUsers = new Set(entries.map(e => e.userId).filter(Boolean)).size;
const totalSearches = entries.length;
const avgResultCount = entries.reduce((s, e) => s + e.resultCount, 0) / totalSearches;
const totalClicks = entries.reduce((s, e) => s + e.clickCount, 0);
const clickThroughRate = totalSearches > 0 ? totalClicks / totalSearches : 0;
const lastSearched = entries.reduce((latest, e) =>
e.timestamp > latest ? e.timestamp : latest, entries[0].timestamp
);
return {
term,
totalSearches,
uniqueUsers,
avgResultCount: parseFloat(avgResultCount.toFixed(2)),
clickThroughRate: parseFloat(clickThroughRate.toFixed(4)),
lastSearched
};
}).sort((a, b) => b.totalSearches - a.totalSearches);
}
export function searchVolumeByDay(queries: SearchQuery[]): Map<string, number> {
const volume = new Map<string, number>();
for (const q of queries) {
const day = q.timestamp.toISOString().slice(0, 10);
volume.set(day, (volume.get(day) || 0) + 1);
}
return volume;
}
export function topSearchTerms(aggregations: SearchAggregation[], limit = 10): SearchAggregation[] {
return aggregations.slice(0, limit);
}