code wiki / _hdl_build / nx_search_federated.nx

nx_search_federated.nx source

↩ module page · 149 lines · 7447 B

1// nx_search_federated.nx -- FEDERATED QUERY across every Nishi index, driven by the search-sources MANIFEST. 2// This is the integration CONSUMER: it reads knowledge/index/search_sources.txt (the contract written by 3// nx_search_register) and queries EVERY listed index -- the ecosystem library index AND the researcher's growing 4// shards AND any future index -- through one interface. It has NO hardcoded index paths and NO knowledge of 5// "researcher" vs "library": it just queries whatever the manifest lists. Adding a new index source needs ZERO 6// change here = loose coupling. Merges candidates across sources, ranks by #query-terms-matched, prints top-K 7// `score [label] path`. Usage: nx_search_federated <term> [term ...] expect_exit: 0 license_tier: ORIGINAL 8import "nx_search_inverted_persist.nx" 9 10const FS_TERMS: i64 = 8 11const FS_ROWIDS: i64 = 4096 12const FS_CAND: i64 = 32768 13const FS_TOPK: i64 = 15 14const FS_SRC: i64 = 8192 15 16func fs_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 17func fs_num(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1} sys_write(1,bb,k); return 0 } 18func fs_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 19 20// scan to next space/newline/end 21func fs_scan(buf: *u8, i: i64, end: i64) -> i64 { 22 var p: i64=i; var stop: i64=0 23 while stop==0 { if p>=end { stop=1 } else { if buf[p]==(32 as u8) { stop=1 } else { if buf[p]==(10 as u8) { stop=1 } else { p=p+1 } } } } 24 return p 25} 26 27// parse a docmap (one path/line) IN PLACE: \n -> NUL, record line starts. Returns ndocs. 28func fs_load_docmap(path: *u8, paths_out: *i64, cap: i64) -> i64 { 29 let lenbox: *i64 = sys_mmap(16) as *i64 30 let buf: *u8 = sys_read_file(path, lenbox) 31 if buf == 0 as *u8 { return 0 - 1 } 32 let total: i64 = lenbox[0] 33 var nd: i64 = 0; var start: i64 = 0; var i: i64 = 0 34 while i < total { 35 if buf[i] == (10 as u8) { 36 buf[i] = 0 as u8 37 if i > start { if nd < cap { paths_out[nd] = (buf as i64) + start; nd = nd + 1 } } 38 start = i + 1 39 } 40 i = i + 1 41 } 42 return nd 43} 44 45func main(argc: i64, argv: *i64) -> i64 { 46 if argc < 2 { fs_puts("usage: nx_search_federated <term> [term ...]\n" as *u8); sys_exit(2); return 2 } 47 var nterms: i64 = argc - 1 48 if nterms > FS_TERMS { nterms = FS_TERMS } 49 fs_puts("=== nx_search_federated: query ALL Nishi indexes via the search-sources manifest ===\n" as *u8) 50 51 // ---- read + parse the manifest (the integration contract); NUL-terminate fields IN PLACE ---- 52 let mbox: *i64 = sys_mmap(16) as *i64 53 let man: *u8 = sys_read_file("knowledge/index/search_sources.txt" as *u8, mbox) 54 if man == 0 as *u8 { fs_puts(" NO manifest (run nx_search_register first)\n" as *u8); sys_exit(1); return 1 } 55 let mlen: i64 = mbox[0] 56 let s_label: *i64 = sys_mmap(8*FS_SRC) as *i64 57 let s_idx: *i64 = sys_mmap(8*FS_SRC) as *i64 58 let s_dmap: *i64 = sys_mmap(8*FS_SRC) as *i64 59 var nsrc: i64 = 0 60 var i: i64 = 0 61 while i < mlen { 62 let ls: i64 = i 63 let e1: i64 = fs_scan(man, i, mlen) // label 64 let label_ptr: i64 = (man as i64) + ls 65 var j: i64 = e1; if j<mlen { if man[j]==(32 as u8) { man[j]=0 as u8; j=j+1 } } 66 let idx_ptr: i64 = (man as i64) + j 67 let e2: i64 = fs_scan(man, j, mlen) // idx path 68 var k: i64 = e2; if k<mlen { if man[k]==(32 as u8) { man[k]=0 as u8; k=k+1 } } 69 let dmap_ptr: i64 = (man as i64) + k 70 let e3: i64 = fs_scan(man, k, mlen) // docmap path 71 if e3<mlen { if man[e3]==(32 as u8) { man[e3]=0 as u8 } } 72 man[e1]=0 as u8 // terminate label (safe even if it was space) 73 // advance to end of line 74 var e: i64 = e3; var st: i64=0 75 while st==0 { if e>=mlen { st=1 } else { if man[e]==(10 as u8) { st=1 } else { e=e+1 } } } 76 if e<mlen { man[e]=0 as u8; e=e+1 } 77 if nsrc < FS_SRC { s_label[nsrc]=label_ptr; s_idx[nsrc]=idx_ptr; s_dmap[nsrc]=dmap_ptr; nsrc=nsrc+1 } 78 i = e 79 } 80 81 // ---- query every source; accumulate candidates (score = #query-terms matched) ---- 82 let cand_path: *i64 = sys_mmap(8*FS_CAND) as *i64 83 let cand_score: *i64 = sys_mmap(8*FS_CAND) as *i64 84 let cand_label: *i64 = sys_mmap(8*FS_CAND) as *i64 85 var ncand: i64 = 0 86 let res: *NxInvQueryResult = sys_mmap(64) as *NxInvQueryResult 87 let rowids: *i64 = sys_mmap(8*FS_ROWIDS) as *i64 88 var sources_ok: i64 = 0; var total_docs: i64 = 0 89 var si: i64 = 0 90 while si < nsrc { 91 let idx: *NxInvIndex = nx_inv_load(s_idx[si] as *u8) 92 if idx != 0 as *NxInvIndex { 93 let paths: *i64 = sys_mmap(8*FS_ROWIDS) as *i64 94 let ndocs: i64 = fs_load_docmap(s_dmap[si] as *u8, paths, FS_ROWIDS) 95 if ndocs > 0 { 96 sources_ok = sources_ok + 1 97 total_docs = total_docs + ndocs 98 let hits: *u8 = sys_mmap(ndocs + 8) 99 var t: i64 = 0 100 while t < nterms { 101 let term: *u8 = argv[1+t] as *u8 102 nx_inv_query_term(idx, term, fs_strlen(term), rowids, FS_ROWIDS, res) 103 var ri: i64 = 0 104 while ri < res.n_rowids_filled { 105 let rid: i64 = rowids[ri] 106 if rid >= 0 { if rid < ndocs { hits[rid] = (hits[rid] as i64 + 1) as u8 } } 107 ri = ri + 1 108 } 109 t = t + 1 110 } 111 var di: i64 = 0 112 while di < ndocs { 113 let h: i64 = hits[di] as i64 114 if h > 0 { if ncand < FS_CAND { cand_path[ncand]=paths[di]; cand_score[ncand]=h; cand_label[ncand]=s_label[si]; ncand=ncand+1 } } 115 di = di + 1 116 } 117 } 118 } 119 si = si + 1 120 } 121 122 fs_puts(" sources="); fs_num(sources_ok); fs_puts("/"); fs_num(nsrc) 123 fs_puts(" docs="); fs_num(total_docs); fs_puts(" candidates="); fs_num(ncand); fs_puts("\n" as *u8) 124 if ncand == 0 { fs_puts(" no match across the federated index\n" as *u8); sys_exit(0); return 0 } 125 126 // ---- rank desc by score, top-K ---- 127 var a: i64 = 0 128 while a < ncand { 129 var best: i64 = a; var b: i64 = a+1 130 while b < ncand { if cand_score[b] > cand_score[best] { best=b } b=b+1 } 131 if best != a { 132 let ts: i64=cand_score[a]; cand_score[a]=cand_score[best]; cand_score[best]=ts 133 let tp: i64=cand_path[a]; cand_path[a]=cand_path[best]; cand_path[best]=tp 134 let tl: i64=cand_label[a]; cand_label[a]=cand_label[best]; cand_label[best]=tl 135 } 136 a=a+1 137 } 138 var topk: i64 = ncand 139 if topk > FS_TOPK { topk = FS_TOPK } 140 fs_puts(" TOP RESULTS across all indexes (score = #query-terms matched):\n" as *u8) 141 var r: i64 = 0 142 while r < topk { 143 fs_puts(" #"); fs_num(r+1); fs_puts(" score="); fs_num(cand_score[r]) 144 fs_puts(" ["); fs_puts(cand_label[r] as *u8); fs_puts("] "); fs_puts(cand_path[r] as *u8); fs_puts("\n" as *u8) 145 r = r + 1 146 } 147 fs_puts(" FEDERATED-OK\n" as *u8) 148 sys_exit(0); return 0 149}