chore: initial commit - CloudSearch v0.0.2
This commit is contained in:
125
packages/backend/src/search/search-optimizer.ts
Executable file
125
packages/backend/src/search/search-optimizer.ts
Executable file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Search Results Optimizer
|
||||
*
|
||||
* For each cloud type, keep only the top N most relevant results.
|
||||
* Order groups by priority: real cloud storage > other providers > magnet/others.
|
||||
*
|
||||
* Goal: give users a manageable, high-quality result set instead of overwhelming them
|
||||
* with hundreds of results dominated by magnet links.
|
||||
*/
|
||||
|
||||
import { detectCloudType } from '../config/cloud-labels';
|
||||
|
||||
/** Minimal result shape the optimizer needs */
|
||||
interface OptimizableResult {
|
||||
title?: string;
|
||||
url?: string;
|
||||
source?: string;
|
||||
score?: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** Priority tiers for result ordering */
|
||||
const CLOUD_PRIORITY: Record<string, number> = {
|
||||
// Tier 1: Major cloud storage (most useful for save-to-cloud feature)
|
||||
baidu: 10,
|
||||
quark: 10,
|
||||
aliyun: 10,
|
||||
// Tier 2: Other cloud storage
|
||||
'115': 20,
|
||||
tianyi: 20,
|
||||
'123pan': 20,
|
||||
uc: 20,
|
||||
xunlei: 20,
|
||||
pikpak: 20,
|
||||
// Tier 3: Mobile/app links (not very useful)
|
||||
mobile: 50,
|
||||
// Tier 4: Direct links (lowest utility for cloud saving)
|
||||
magnet: 100,
|
||||
ed2k: 100,
|
||||
others: 100,
|
||||
};
|
||||
|
||||
const DEFAULT_PRIORITY = 50;
|
||||
|
||||
/** Get cloud type for a result, with an extra check for tracker URLs */
|
||||
function getCloudType(result: OptimizableResult): string {
|
||||
const url = result.url;
|
||||
// Check for tracker/private-site URLs not covered by shared detection
|
||||
if (url && /mteam|hdarea|hdsky/i.test(url)) return 'others';
|
||||
return detectCloudType(url);
|
||||
}
|
||||
|
||||
function getPriority(cloudType: string): number {
|
||||
return CLOUD_PRIORITY[cloudType] ?? DEFAULT_PRIORITY;
|
||||
}
|
||||
|
||||
export interface OptimizationResult {
|
||||
results: OptimizableResult[];
|
||||
/** Per-type stats for display */
|
||||
perType: Array<{ type: string; count: number; total: number }>;
|
||||
/** How many items were kept vs filtered */
|
||||
keptCount: number;
|
||||
filteredCount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize search results:
|
||||
* 1. Group by cloud type
|
||||
* 2. Sort by score descending within each group
|
||||
* 3. Keep only top `maxPerType` results per type
|
||||
* 4. Order groups by priority (cloud storage first)
|
||||
*/
|
||||
export function optimizeSearchResults(
|
||||
items: OptimizableResult[],
|
||||
maxPerType: number = 20
|
||||
): OptimizationResult {
|
||||
// Step 1: Group by cloud type
|
||||
const grouped: Record<string, OptimizableResult[]> = {};
|
||||
const typeTotals: Record<string, number> = {};
|
||||
|
||||
for (const item of items) {
|
||||
const ct = getCloudType(item);
|
||||
if (!grouped[ct]) {
|
||||
grouped[ct] = [];
|
||||
}
|
||||
grouped[ct].push(item);
|
||||
typeTotals[ct] = (typeTotals[ct] || 0) + 1;
|
||||
}
|
||||
|
||||
// Step 2 & 3: Sort each group by score desc, take top N
|
||||
const kept: OptimizableResult[] = [];
|
||||
const perType: Array<{ type: string; count: number; total: number }> = [];
|
||||
|
||||
for (const [ct, groupItems] of Object.entries(grouped)) {
|
||||
// Sort by score descending (higher score = more relevant)
|
||||
groupItems.sort((a, b) => (b.score || 0) - (a.score || 0));
|
||||
|
||||
const top = groupItems.slice(0, maxPerType);
|
||||
kept.push(...top);
|
||||
|
||||
perType.push({
|
||||
type: ct,
|
||||
count: top.length,
|
||||
total: typeTotals[ct],
|
||||
});
|
||||
}
|
||||
|
||||
// Step 4: Sort kept results by cloud priority, then by score within same priority
|
||||
kept.sort((a, b) => {
|
||||
const pa = getPriority(getCloudType(a));
|
||||
const pb = getPriority(getCloudType(b));
|
||||
if (pa !== pb) return pa - pb;
|
||||
return (b.score || 0) - (a.score || 0);
|
||||
});
|
||||
|
||||
const keptCount = kept.length;
|
||||
const filteredCount = items.length - keptCount;
|
||||
|
||||
return {
|
||||
results: kept,
|
||||
perType,
|
||||
keptCount,
|
||||
filteredCount,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user