File size: 2,127 Bytes
7e2d97f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
"""
Déduplication de la base ChromaDB
=================================
Supprime les chunks redondants : quand une même paire (source, chunk_index)
existe plusieurs fois (= fichier ingéré plusieurs fois), on garde 1 exemplaire
et on supprime les autres. Lecture/écriture locale, AUCUN appel Azure.

Usage : ./.venv/Scripts/python.exe dedup_store.py
"""

import os
from pathlib import Path
from collections import defaultdict

os.environ.setdefault("ANONYMIZED_TELEMETRY", "False")
import chromadb
from chromadb.config import Settings

PROJECT_ROOT = Path(__file__).parent
DATA_DIR = Path("/data") if Path("/data").is_dir() else PROJECT_ROOT / "data"
COLLECTION_NAME = "rag_documents"

client = chromadb.PersistentClient(path=str(DATA_DIR / "chroma_db"), settings=Settings(anonymized_telemetry=False))
col = client.get_or_create_collection(name=COLLECTION_NAME, metadata={"hnsw:space": "cosine"})

total = col.count()
print(f"Total chunks avant : {total}")

# (source, chunk_index) -> liste d'ids
pair_to_ids = defaultdict(list)
off, step = 0, 2000
while off < total:
    got = col.get(include=["metadatas"], limit=step, offset=off)
    for _id, m in zip(got["ids"], got["metadatas"]):
        pair_to_ids[(m.get("source"), m.get("chunk_index"))].append(_id)
    off += step

# pour chaque paire en double, on garde le 1er id, on supprime les autres
to_delete = []
affected = defaultdict(int)
for (src, idx), ids in pair_to_ids.items():
    if len(ids) > 1:
        extra = ids[1:]            # on garde ids[0]
        to_delete.extend(extra)
        affected[src] += len(extra)

print(f"Chunks redondants à supprimer : {len(to_delete)}")
print("Mémoires concernés :")
for src, n in sorted(affected.items(), key=lambda x: -x[1]):
    print(f"   -{n}  {src}")

if not to_delete:
    print("Aucun doublon. Rien à faire.")
else:
    # suppression par lots (limite SQLite sur le nombre de variables)
    B = 500
    for i in range(0, len(to_delete), B):
        col.delete(ids=to_delete[i:i + B])
        print(f"  supprimé {min(i + B, len(to_delete))}/{len(to_delete)}")
    print(f"Total chunks après : {col.count()}")