Files
hlamingo/tools/reindex.py
T
alexandClaude Opus 5 39c807d4de Эмбеддер bge-m3: смысловой поиск на русском наконец разделяет смыслы
nomic-embed-text на русском не работал: в замере «велосипедная камера»
набирала мультиметру 0.704 — больше, чем верный ответ на «паяльник» (0.691).
Зазор −0.013, то есть мусор систематически обгонял правильное и порогом это
не лечилось.

bge-m3 на том же наборе: верные не ниже 0.537, мусор не выше 0.460,
зазор +0.077. Префиксы задачи ему не нужны, поэтому обнулены.

Порог откалиброван на настоящей базе, а не на придуманном наборе, и картина
там честнее: абстрактное «чем посветить» набирает лампам 0.411, а посторонняя
«детская коляска» — 0.535. Полностью не разделяются, поэтому SEMANTIC_MIN
выставлен так, чтобы отсечь весь мусор ценой слабых догадок — уверенно
показанное не то хуже честного «не нашёл». Точных запросов это не касается:
они находятся по словам и тегам.

Добавлен tools/reindex.py: смена эмбеддера требует полного пересчёта векторов,
иначе смешанная база тихо портит поиск. Скрипт делает копию перед работой.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 18:23:22 +03:00

72 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""Пересчёт векторов после смены модели эмбеддера.
Векторы разных моделей несовместимы: если половина базы посчитана одной
моделью, а половина другой, косинус между ними — шум, и поиск тихо портится,
ничем себя не выдавая. Поэтому при смене EMBED_MODEL нужен полный пересчёт.
Запуск (сервер лучше остановить, чтобы не писал в базу одновременно):
venv\\Scripts\\python.exe tools\\reindex.py
"""
import io
import os
import sys
import time
import shutil
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
try:
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
except Exception:
pass
from hlamingo import store, search, ollama, config # noqa: E402
def main():
if not config.DB_FILE.exists():
print("База пуста — пересчитывать нечего.")
return 0
if not ollama.check():
print("Ollama недоступна (%s) — без неё векторы не посчитать." % config.OLLAMA_HOST)
return 1
db = store.load()
total = len(db["items"])
print("Модель эмбеддера: %s" % config.EMBED_MODEL)
print("Вещей в базе: %d" % total)
if not total:
return 0
# Своя копия рядом с автоматическими: пересчёт трогает каждую запись.
backup = config.DATA_DIR / "backups" / ("db-before-reindex-%s.json"
% time.strftime("%Y%m%d-%H%M%S"))
backup.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(str(config.DB_FILE), str(backup))
print("Копия: %s\n" % backup.name)
t0 = time.time()
done = 0
for item in db["items"].values():
item["emb"] = None
for item in db["items"].values():
vector = ollama.embed(search.item_text(item))
if not vector:
print(" не удалось посчитать: %s" % item.get("name"))
continue
item["emb"] = vector
done += 1
print(" [%d/%d] %s" % (done, total, item.get("name")))
store.save(db)
print("\nГотово: %d из %d за %.1f с." % (done, total, time.time() - t0))
if done < total:
print("Часть векторов не посчиталась — запусти ещё раз, когда Ollama ответит.")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())