scripts/reset_qdrant.py aktualisiert
Some checks failed
Deploy mindnet to llm-node / deploy (push) Failing after 2s

This commit is contained in:
Lars 2025-09-05 07:12:47 +02:00
parent 566fe813b9
commit 5a089b6262

View File

@ -1,95 +1,156 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Name: scripts/reset_qdrant.py Name: scripts/reset_qdrant.py
Version: v1.0.0 (2025-09-04) Version: v1.1.0 (2025-09-04)
Kurzbeschreibung: Kurzbeschreibung:
Löscht entweder die gesamten mindnet-Collections (Wipe) und legt sie gemäß Sicheres Zurücksetzen der Qdrant-Collections für EIN Projektpräfix. Das Skript
Projekt-Defaults neu an, oder löscht nur alle Punkte (Truncate), wobei die ermittelt zunächst die tatsächlich betroffenen Collections und zeigt eine
Collection-Konfiguration erhalten bleibt. Übersicht an. Anschließend wird der User um Bestätigung gebeten (interaktive
Abfrage), bevor eine der beiden Aktionen ausgeführt wird:
- wipe: Löscht die Collections komplett und legt sie gemäß Projekt-Defaults neu an
- truncate: Löscht nur alle Points (Inhalte), behält die Collection-Settings
Aufruf (aus Projekt-Root, im venv): Aufruf (aus Projekt-Root, im venv):
python3 -m scripts.reset_qdrant --mode wipe [--prefix PREFIX] python3 -m scripts.reset_qdrant --mode wipe [--prefix PREFIX] [--yes] [--dry-run]
python3 -m scripts.reset_qdrant --mode truncate [--prefix PREFIX] python3 -m scripts.reset_qdrant --mode truncate [--prefix PREFIX] [--yes] [--dry-run]
Parameter: Parameter:
--mode wipe | truncate --mode wipe | truncate (Pflicht)
--prefix Collection-Prefix (Default: env COLLECTION_PREFIX oder 'mindnet') --prefix Collection-Prefix (Default: env COLLECTION_PREFIX oder 'mindnet')
--yes Keine Rückfrage, direkt ausführen (CI/CD geeignet)
--dry-run Nur anzeigen, was passieren würde; nichts ändern
Umgebungsvariablen (optional): Umgebungsvariablen (optional):
QDRANT_URL, QDRANT_API_KEY, COLLECTION_PREFIX, VECTOR_DIM (Default 384) QDRANT_URL, QDRANT_API_KEY, COLLECTION_PREFIX, VECTOR_DIM (Default 384)
Sicherheitsmerkmale:
- Betrachtet ausschließlich Collections des angegebenen Präfixes.
- Listet vor Ausführung die tatsächlich existierenden Ziel-Collections auf.
- Fragt interaktiv nach Bestätigung (es sei denn --yes ist gesetzt).
Hinweise: Exitcodes:
- Wipe: Collections werden komplett gelöscht und via ensure_collections() neu 0 = OK, 1 = abgebrochen/keine Aktion, 2 = Verbindungs-/Konfigurationsfehler
erstellt (Notes/Chunks: 384d/COSINE; Edges: 1d/DOT).
- Truncate: löscht nur Points (behält Settings/Indexing).
Changelog: Changelog:
v1.0.0: Initiale Version. v1.1.0: Interaktive Bestätigung, --yes/--dry-run hinzugefügt, Preview der betroffenen Collections.
v1.0.0: Wipe/Truncate ohne Bestätigungsabfrage.
""" """
from __future__ import annotations from __future__ import annotations
import argparse import argparse
import os
import sys
from typing import List
from qdrant_client import QdrantClient from qdrant_client import QdrantClient
from qdrant_client.http import models as rest from qdrant_client.http import models as rest
from app.core.qdrant import QdrantConfig, get_client, ensure_collections, collection_names from app.core.qdrant import QdrantConfig, get_client, ensure_collections, collection_names
def resolve_existing_collections(client: QdrantClient, prefix: str) -> List[str]:
"""Ermittelt die *existierenden* Collections für das übergebene Präfix.
Es werden NUR die projektdefinierten Collections betrachtet (notes/chunks/edges).
"""
notes, chunks, edges = collection_names(prefix)
candidates = [notes, chunks, edges]
existing = [c for c in candidates if client.collection_exists(c)]
return existing
def delete_all_points(client: QdrantClient, collections): def confirm_or_abort(action: str, collections: List[str], nonexisting: List[str], assume_yes: bool) -> bool:
match_all = rest.Filter(must=[]) print("\n=== Reset-Vorschau ===")
for col in collections: print(f"Aktion: {action}")
if client.collection_exists(col): if collections:
client.delete_points(collection_name=col, points_selector=match_all, wait=True) print("Betroffen (existieren):")
for c in collections:
print(f" - {c}")
else:
print("Betroffen (existieren): — (keine)")
if nonexisting:
print("Nicht vorhanden (werden bei wipe ggf. neu angelegt):")
for c in nonexisting:
print(f" - {c}")
if assume_yes:
print("\n--yes gesetzt → führe ohne Rückfrage aus.")
return True
try:
ans = input("\nFortfahren? (yes/no): ").strip().lower()
except EOFError:
return False
return ans in ("y", "yes")
def delete_all_points(client: QdrantClient, collections: List[str]) -> None:
match_all = rest.Filter(must=[])
for col in collections:
client.delete_points(collection_name=col, points_selector=match_all, wait=True)
def wipe_collections(client: QdrantClient, collections): def wipe_collections(client: QdrantClient, all_col_names: List[str], existing: List[str]) -> None:
for col in collections: # Lösche nur Collections, die wirklich existieren; die anderen werden anschließend neu angelegt
if client.collection_exists(col): for col in existing:
client.delete_collection(col) client.delete_collection(col)
# ensure_collections legt alle benötigten Collections (notes/chunks/edges) neu an
def main(): def main():
ap = argparse.ArgumentParser(description="Wipe oder truncate mindnet-Collections in Qdrant.") ap = argparse.ArgumentParser(description="Wipe oder truncate mindnet-Collections in Qdrant (mit Bestätigung).")
ap.add_argument("--mode", choices=["wipe", "truncate"], required=True, ap.add_argument("--mode", choices=["wipe", "truncate"], required=True,
help="wipe = Collections löschen & neu anlegen; truncate = nur Inhalte löschen") help="wipe = Collections löschen & neu anlegen; truncate = nur Inhalte löschen")
ap.add_argument("--prefix", help="Collection-Prefix (Default: env COLLECTION_PREFIX oder 'mindnet')") ap.add_argument("--prefix", help="Collection-Prefix (Default: env COLLECTION_PREFIX oder 'mindnet')")
args = ap.parse_args() ap.add_argument("--yes", action="store_true", help="Ohne Rückfrage ausführen (CI/CD)")
ap.add_argument("--dry-run", action="store_true", help="Nur anzeigen, was passieren würde; nichts ändern")
args = ap.parse_args()
# Qdrant-Konfiguration
try:
cfg = QdrantConfig.from_env()
except Exception as e:
print(f"Konfigurationsfehler: {e}", file=sys.stderr)
sys.exit(2)
cfg = QdrantConfig.from_env() if args.prefix:
if args.prefix: cfg.prefix = args.prefix
cfg.prefix = args.prefix
# Client
try:
client = get_client(cfg)
except Exception as e:
print(f"Verbindungsfehler zu Qdrant: {e}", file=sys.stderr)
sys.exit(2)
client = get_client(cfg) # Ziel-Collections: existierende & nicht existierende (per Namenskonvention)
notes, chunks, edges = collection_names(cfg.prefix) notes, chunks, edges = collection_names(cfg.prefix)
cols = [notes, chunks, edges] all_col_names = [notes, chunks, edges]
existing = resolve_existing_collections(client, cfg.prefix)
nonexisting = [c for c in all_col_names if c not in existing]
# Preview & Bestätigung
if not confirm_or_abort(args.mode, existing, nonexisting, args.yes):
print("Abgebrochen keine Änderungen vorgenommen.")
sys.exit(1)
if args.mode == "wipe": if args.dry_run:
wipe_collections(client, cols) print("Dry-Run keine Änderungen vorgenommen.")
ensure_collections(client, cfg.prefix, cfg.dim) sys.exit(0)
print(f"Wiped & recreated: {cols}")
else:
delete_all_points(client, cols)
print(f"Truncated (deleted all points in): {cols}")
# Ausführen
if args.mode == "wipe":
wipe_collections(client, all_col_names, existing)
ensure_collections(client, cfg.prefix, cfg.dim)
print(f"Wiped & recreated (Prefix={cfg.prefix}): {all_col_names}")
else:
if not existing:
print("Keine existierenden Collections zum Truncaten gefunden. Beende ohne Aktion.")
sys.exit(0)
delete_all_points(client, existing)
print(f"Truncated (deleted all points in): {existing}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()