(args=None)
| 15 | |
| 16 | |
| 17 | def main(args=None) -> None: |
| 18 | # 1. Load queries and ground truth |
| 19 | queries = read_fvecs(args.query_file) |
| 20 | gt = read_ivecs(args.gt_file) |
| 21 | nq = queries.shape[0] |
| 22 | print(f"Queries: {queries.shape}, GT: {gt.shape}") |
| 23 | |
| 24 | # 2. Load index |
| 25 | idx = HnswIndex.load(args.index_file) |
| 26 | print(f"Index loaded — dim={idx.dim}") |
| 27 | print(f"TopK: {args.topk}") |
| 28 | |
| 29 | print("\nsearch start >.....\n") |
| 30 | |
| 31 | all_qps = np.zeros((args.test_rounds, len(EFS))) |
| 32 | all_recall = np.zeros((args.test_rounds, len(EFS))) |
| 33 | |
| 34 | for i_probe, ef in enumerate(EFS): |
| 35 | for r in range(args.test_rounds): |
| 36 | t0 = time() |
| 37 | ids, _ = idx.search(queries, k=args.topk, ef=ef, num_threads=args.num_threads) |
| 38 | elapsed = time() - t0 # seconds |
| 39 | |
| 40 | qps = nq / elapsed |
| 41 | recall = compute_recall(ids, gt, args.topk) |
| 42 | |
| 43 | all_qps[r, i_probe] = qps |
| 44 | all_recall[r, i_probe] = recall |
| 45 | |
| 46 | avg_qps = all_qps.mean(axis=0) |
| 47 | avg_recall = all_recall.mean(axis=0) |
| 48 | |
| 49 | # 3. Print results table |
| 50 | print(f"{'EF':<8}{'QPS':<14}{'Recall'}") |
| 51 | print("-" * 35) |
| 52 | for i, ef in enumerate(EFS): |
| 53 | print(f"{ef:<8}{avg_qps[i]:<14.1f}{avg_recall[i]:<12.4f}") |
| 54 | |
| 55 | |
| 56 | if __name__ == "__main__": |
no test coverage detected