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
# -*- coding: utf-8 -*-
"""
Name: scripts/reset_qdrant.py
Version: v1.0.0 (2025-09-04)
Name: scripts/reset_qdrant.py
Version: v1.1.0 (2025-09-04)
Kurzbeschreibung:
Löscht entweder die gesamten mindnet-Collections (Wipe) und legt sie gemäß
Projekt-Defaults neu an, oder löscht nur alle Punkte (Truncate), wobei die
Collection-Konfiguration erhalten bleibt.
Sicheres Zurücksetzen der Qdrant-Collections für EIN Projektpräfix. Das Skript
ermittelt zunächst die tatsächlich betroffenen Collections und zeigt eine
Ü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):
python3 -m scripts.reset_qdrant --mode wipe [--prefix PREFIX]
python3 -m scripts.reset_qdrant --mode truncate [--prefix PREFIX]
python3 -m scripts.reset_qdrant --mode wipe [--prefix PREFIX] [--yes] [--dry-run]
python3 -m scripts.reset_qdrant --mode truncate [--prefix PREFIX] [--yes] [--dry-run]
Parameter:
--mode wipe | truncate
--prefix Collection-Prefix (Default: env COLLECTION_PREFIX oder 'mindnet')
--mode wipe | truncate (Pflicht)
--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):
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:
- Wipe: Collections werden komplett gelöscht und via ensure_collections() neu
erstellt (Notes/Chunks: 384d/COSINE; Edges: 1d/DOT).
- Truncate: löscht nur Points (behält Settings/Indexing).
Exitcodes:
0 = OK, 1 = abgebrochen/keine Aktion, 2 = Verbindungs-/Konfigurationsfehler
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
import argparse
import os
import sys
from typing import List
from qdrant_client import QdrantClient
from qdrant_client.http import models as rest
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):
match_all = rest.Filter(must=[])
for col in collections:
if client.collection_exists(col):
client.delete_points(collection_name=col, points_selector=match_all, wait=True)
def confirm_or_abort(action: str, collections: List[str], nonexisting: List[str], assume_yes: bool) -> bool:
print("\n=== Reset-Vorschau ===")
print(f"Aktion: {action}")
if collections:
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):
for col in collections:
if client.collection_exists(col):
client.delete_collection(col)
def wipe_collections(client: QdrantClient, all_col_names: List[str], existing: List[str]) -> None:
# Lösche nur Collections, die wirklich existieren; die anderen werden anschließend neu angelegt
for col in existing:
client.delete_collection(col)
# ensure_collections legt alle benötigten Collections (notes/chunks/edges) neu an
def main():
ap = argparse.ArgumentParser(description="Wipe oder truncate mindnet-Collections in Qdrant.")
ap.add_argument("--mode", choices=["wipe", "truncate"], required=True,
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')")
args = ap.parse_args()
ap = argparse.ArgumentParser(description="Wipe oder truncate mindnet-Collections in Qdrant (mit Bestätigung).")
ap.add_argument("--mode", choices=["wipe", "truncate"], required=True,
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("--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:
cfg.prefix = args.prefix
if 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)
notes, chunks, edges = collection_names(cfg.prefix)
cols = [notes, chunks, edges]
# Ziel-Collections: existierende & nicht existierende (per Namenskonvention)
notes, chunks, edges = collection_names(cfg.prefix)
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":
wipe_collections(client, cols)
ensure_collections(client, cfg.prefix, cfg.dim)
print(f"Wiped & recreated: {cols}")
else:
delete_all_points(client, cols)
print(f"Truncated (deleted all points in): {cols}")
if args.dry_run:
print("Dry-Run keine Änderungen vorgenommen.")
sys.exit(0)
# 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__":
main()
main()