code wiki / _hdl_build / nx_search_relevance_bench.nx
nx_search_relevance_bench.nx source
↩ module page · 101 lines · 5280 B
1// nx_search_relevance_bench.nx -- MEASURED RELEVANCE for nishi search (operator 2026-07-03: "make sure
2// ... we are state of the art" -- SOTA is a measured quality, not a checklist). A judged query set over
3// the REAL library shard (dp-nishifamily.com-pub-, 596 docs): each query names the marker string its
4// correct doc must contain; we run the FULL ranked search and score:
5// MRR@5 (mean reciprocal rank, Q10: 1024/rank, the sota_mrr.html canon)
6// mean DCG@5 gain (Q10: 1024*1024/ilog2_1024(rank+1) -- binary judgments, the sota_ndcg.html canon)
7// Prints per-query ranks + aggregates; GREEN floor = MRR >= 768 (0.75) -- a RATCHET: raise it as the
8// engine improves, never lower it. license_tier: ORIGINAL
9import "nx_docportal_search_serve.nx"
10import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
11const K_MAGIC_1024: i64 = 1024
12
13func rb_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
14func rb_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
15// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
16// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
17// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
18// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
19func rb_num(v: i64) -> i64 { nxi_out(v); return 0 }
20func rb_contains(hay: *u8, hn: i64, ndl: *u8) -> i64 {
21 let nl: i64 = rb_len(ndl)
22 if nl == 0 { return 0 }
23 var i: i64 = 0
24 while i + nl <= hn {
25 var m: i64 = 1
26 var j: i64 = 0
27 while j < nl { if hay[i + j] != ndl[j] { m = 0; j = nl } else { j = j + 1 } }
28 if m == 1 { return 1 }
29 i = i + 1
30 }
31 return 0
32}
33// rank (1-based) of the first top-5 result whose doc text contains `marker`; 0 = not found in top 5
34func rb_rank(dom: *u8, q: *u8, marker: *u8) -> i64 {
35 let cids: *i64 = sys_mmap(8 * 8) as *i64
36 let scores: *i64 = sys_mmap(8 * 8) as *i64
37 let n: i64 = dss_search(dom, q, rb_len(q), cids, scores, 5)
38 if n <= 0 { return 0 }
39 let prefix: *u8 = sys_mmap(512); dss_prefix(dom, prefix)
40 let h: *i64 = ss_open(prefix)
41 if (h as i64) == 0 { return 0 }
42 let key: *u8 = sys_mmap(64)
43 let dp: *i64 = sys_mmap(16) as *i64
44 let dl: *i64 = sys_mmap(16) as *i64
45 var i: i64 = 0
46 while i < n {
47 dss_mkkey(cids[i], key)
48 if ss_hget(h, key, dp, dl) == 1 {
49 if rb_contains(dp[0] as *u8, dl[0], marker) == 1 { return i + 1 }
50 }
51 i = i + 1
52 }
53 return 0
54}
55func rb_one(dom: *u8, q: *u8, marker: *u8, mrrsum: *i64, dcgsum: *i64, hits1: *i64, nq: *i64) -> i64 {
56 let r: i64 = rb_rank(dom, q, marker)
57 nq[0] = nq[0] + 1
58 rb_puts(" [" as *u8); rb_puts(q); rb_puts("] rank=" as *u8); rb_num(r)
59 if r >= 1 {
60 mrrsum[0] = mrrsum[0] + K_MAGIC_1024 / r
61 dcgsum[0] = dcgsum[0] + (K_MAGIC_1024 * K_MAGIC_1024) / ilog2_1024(r + 1)
62 if r == 1 { hits1[0] = hits1[0] + 1 }
63 rb_puts("\n" as *u8)
64 } else {
65 rb_puts(" MISS\n" as *u8)
66 }
67 return 0
68}
69
70func main() -> i64 {
71 rb_puts("=== nishi search RELEVANCE bench (judged set over the 596-doc library; MRR@5 + DCG@5, integer) ===\n" as *u8)
72 let dom: *u8 = "nishifamily.com" as *u8
73 let mrrsum: *i64 = sys_mmap(16) as *i64; mrrsum[0] = 0
74 let dcgsum: *i64 = sys_mmap(16) as *i64; dcgsum[0] = 0
75 let hits1: *i64 = sys_mmap(16) as *i64; hits1[0] = 0
76 let nq: *i64 = sys_mmap(16) as *i64; nq[0] = 0
77
78 rb_one(dom, "okapi bm25" as *u8, "Okapi BM25" as *u8, mrrsum, dcgsum, hits1, nq)
79 rb_one(dom, "flashattention memory" as *u8, "FlashAttention" as *u8, mrrsum, dcgsum, hits1, nq)
80 rb_one(dom, "meilisearch" as *u8, "Meilisearch" as *u8, mrrsum, dcgsum, hits1, nq)
81 rb_one(dom, "pagerank algorithm" as *u8, "PageRank" as *u8, mrrsum, dcgsum, hits1, nq)
82 rb_one(dom, "inverted index" as *u8, "Inverted index" as *u8, mrrsum, dcgsum, hits1, nq)
83 rb_one(dom, "web crawler" as *u8, "Web crawler" as *u8, mrrsum, dcgsum, hits1, nq)
84 rb_one(dom, "featured snippet" as *u8, "Featured snippet" as *u8, mrrsum, dcgsum, hits1, nq)
85 rb_one(dom, "knowledge panel" as *u8, "Knowledge panel" as *u8, mrrsum, dcgsum, hits1, nq)
86 rb_one(dom, "typesense" as *u8, "Typesense" as *u8, mrrsum, dcgsum, hits1, nq)
87 rb_one(dom, "duckduckgo privacy" as *u8, "DuckDuckGo" as *u8, mrrsum, dcgsum, hits1, nq)
88 rb_one(dom, "\"ranking function\"" as *u8, "Okapi BM25" as *u8, mrrsum, dcgsum, hits1, nq)
89 rb_one(dom, "stract" as *u8, "Stract" as *u8, mrrsum, dcgsum, hits1, nq)
90
91 let mrr: i64 = mrrsum[0] / nq[0]
92 let dcg: i64 = dcgsum[0] / nq[0]
93 rb_puts("----\nqueries=" as *u8); rb_num(nq[0])
94 rb_puts(" hit@1=" as *u8); rb_num(hits1[0])
95 rb_puts(" MRR@5_q10=" as *u8); rb_num(mrr)
96 rb_puts(" (" as *u8); rb_num((mrr * 1000) / K_MAGIC_1024); rb_puts("/1000)" as *u8)
97 rb_puts(" meanDCG@5_q10=" as *u8); rb_num(dcg); rb_puts("\n" as *u8)
98 if mrr >= 768 { rb_puts("RELEVANCE-BENCH GREEN (ratchet floor MRR>=0.75; raise as the engine improves)\n" as *u8); return 0 }
99 rb_puts("RELEVANCE-BENCH RED (below the ratchet floor)\n" as *u8)
100 return 1
101}