| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- #!/usr/bin/env python3
- """
- Optimize RAG keyword index:
- 1. Prune useless keywords (too frequent / too rare)
- 2. Use pickle for fast loading
- 3. Store chunk_id as int index instead of string
- """
- import json
- import pickle
- import time
- import re
- from pathlib import Path
- from collections import Counter
- BASE = Path("/data/knowledge/maritime")
- INDEX_FILE = BASE / "rag_index.json"
- KEYWORD_FILE = BASE / "rag_index.keywords.json"
- # Optimized outputs
- OPT_INDEX = BASE / "rag_index.pkl"
- OPT_KEYWORDS = BASE / "rag_keywords.pkl"
- print("=== RAG Index Optimizer ===")
- # Load original
- print("Loading chunk index...")
- t0 = time.time()
- with open(INDEX_FILE) as f:
- data = json.load(f)
- chunks = data["chunks"]
- print(f" Chunks: {len(chunks)}, loaded in {time.time()-t0:.1f}s")
- print("Loading keyword index...")
- t0 = time.time()
- with open(KEYWORD_FILE) as f:
- keywords = json.load(f)
- t1 = time.time()
- print(f" Keywords: {len(keywords)}, loaded in {t1-t0:.1f}s")
- # Analyze
- lengths = [len(v) for v in keywords.values()]
- print(f"\n--- Before optimization ---")
- print(f" Total keywords: {len(keywords)}")
- print(f" Total postings: {sum(lengths)}")
- print(f" Avg postings/keyword: {sum(lengths)/len(lengths):.1f}")
- print(f" Max postings: {max(lengths)}")
- # Build chunk_id -> int index mapping
- chunk_ids = [c["id"] for c in chunks]
- id_to_idx = {cid: i for i, cid in enumerate(chunk_ids)}
- # Prune keywords
- MIN_FREQ = 2 # Keywords appearing in <2 chunks are noise
- MAX_FREQ_PCT = 0.3 # Keywords appearing in >30% of chunks are too common (stopwords)
- max_freq = int(len(chunks) * MAX_FREQ_PCT)
- pruned = {}
- removed_rare = 0
- removed_common = 0
- for kw, posting_list in keywords.items():
- n = len(posting_list)
- if n < MIN_FREQ:
- removed_rare += 1
- continue
- if n > max_freq:
- removed_common += 1
- continue
- # Convert string IDs to int indices for compact storage
- int_postings = []
- for cid in posting_list:
- if cid in id_to_idx:
- int_postings.append(id_to_idx[cid])
- if int_postings:
- pruned[kw] = int_postings
- print(f"\n--- After pruning ---")
- print(f" Removed rare (<{MIN_FREQ}): {removed_rare}")
- print(f" Removed common (>{max_freq}): {removed_common}")
- print(f" Remaining keywords: {len(pruned)}")
- print(f" Total postings: {sum(len(v) for v in pruned.values())}")
- # Build optimized chunk data (minimal fields)
- opt_chunks = []
- for c in chunks:
- opt_chunks.append({
- "id": c["id"],
- "source": c["source"],
- "chunk_id": c["chunk_id"],
- "text": c["text"],
- "length": c["length"],
- })
- # Save as pickle
- print("\nSaving optimized index (pickle)...")
- t0 = time.time()
- opt_data = {
- "total_chunks": len(opt_chunks),
- "total_files": data.get("total_files", 0),
- "chunk_size": data.get("chunk_size", 512),
- "chunks": opt_chunks,
- "chunk_ids": chunk_ids, # for reverse lookup
- }
- with open(OPT_INDEX, "wb") as f:
- pickle.dump(opt_data, f, protocol=pickle.HIGHEST_PROTOCOL)
- with open(OPT_KEYWORDS, "wb") as f:
- pickle.dump(pruned, f, protocol=pickle.HIGHEST_PROTOCOL)
- t1 = time.time()
- print(f" Saved in {t1-t0:.1f}s")
- # File sizes
- idx_size = OPT_INDEX.stat().st_size / 1024 / 1024
- kw_size = OPT_KEYWORDS.stat().st_size / 1024 / 1024
- old_kw_size = KEYWORD_FILE.stat().st_size / 1024 / 1024
- print(f"\n--- File sizes ---")
- print(f" Chunk index: {idx_size:.1f} MB (pickle)")
- print(f" Keyword index: {kw_size:.1f} MB (pickle) vs {old_kw_size:.1f} MB (JSON) = {kw_size/old_kw_size*100:.0f}%")
- # Verify load time
- print("\n--- Load time verification ---")
- t0 = time.time()
- with open(OPT_INDEX, "rb") as f:
- d1 = pickle.load(f)
- t1 = time.time()
- with open(OPT_KEYWORDS, "rb") as f:
- d2 = pickle.load(f)
- t2 = time.time()
- print(f" Chunk index load: {(t1-t0)*1000:.0f}ms")
- print(f" Keyword index load: {(t2-t1)*1000:.0f}ms")
- print(f" Total: {(t2-t0)*1000:.0f}ms")
- print(f"\n Speedup: {43000/(t2-t0)/1000:.0f}x faster!")
|