tagsearch — Python Engine
Réalisé par Gillesto66 & Kiro | Moteur de référence du projet TagSearch
Le moteur Python est la source de vérité du projet. C'est ici que les algorithmes sont définis, documentés et validés avant d'être portés en TypeScript et PHP. Toute modification de la formule de scoring doit partir de ce module.
Objectif du module
Fournir un moteur de recherche par tags entièrement in-memory, sans dépendance externe, capable de :
- Indexer des produits e-commerce avec leurs métadonnées (type, niche, prix, localisation, avis)
- Répondre à des requêtes textuelles avec autocomplétion (O(L)) et recherche floue (Levenshtein + pruning)
- Classer les résultats selon 5 dimensions : pertinence BM25, qualité des avis, type de produit, niche, proximité géographique, budget
Architecture des modules
tagsearch/
├── models.py ProductMeta, ProductType, SearchPreferences
├── structures.py Trie, DAWG, VarInt, CompressedPostingsList, LRUCache
├── scoring.py BM25Index, calculate_final_score + constantes canoniques
└── engine.py SearchEngine — point d'entrée public
structures.py — Phase 1 (mémoire)
TrieNodeavec__slots__+ tableau fixe de 38 slots : 83% moins de RAM qu'un objet standardDAWGvia algorithme de Daciuk : partage réel des suffixes (le mot est reconstruit par le chemin, jamais stocké dans le nœud). Gain mesuré sur le nombre de nœuds : 85 % sur un vocabulaire synthétique à suffixes répétés, 50 % en pire cas ; non mesuré sur un vrai catalogue (benchmarks/dawg_vs_trie.py)CompressedPostingsList: delta-encoding + VarInt, −97,5 % de RAM vssetPython sur 500 identifiants (mesuré)
Indexation paresseuse : add_product() / add_products() / load_catalog() n'enregistrent que les données ; le DAWG est reconstruit une seule fois, au premier search() suivant ou via commit(). Charger N produits coûte O(N). load_catalog() est atomique (un produit invalide n'ajoute rien).
Erreurs : seules les ValueError de validation d'entrée (requête vide, max_dist < 0, top_k < 1) sont levées volontairement ; toute autre exception est un vrai bug et remonte telle quelle (elle n'est plus convertie en « aucun résultat »).
scoring.py — Phase 2 (intelligence)
BM25Index: Okapi BM25 in-memory, paramètresk1=1.5,b=0.75calculate_final_score: formule multiplicative 5 dimensions avec Bayesian rating
Installation
# Développement (pas d'installation nécessaire)
cd python-engine
python -m pytest tests/ -v
# Installation dans un autre projet
pip install -e .
Pas besoin de
pip install -e .pour développer —pytesttrouve le package viapythonpath = ["."]danspyproject.toml.
Quick Start
from tagsearch import SearchEngine, ProductMeta, ProductType, SearchPreferences
# Chargement depuis le dataset partagé
engine = SearchEngine(cache_size=200)
engine.load_catalog("../shared-assets/catalog.json")
# Recherche simple
results, status = engine.search("gaming")
# status = "CALCULÉ" | "CACHÉ" | "MISS"
# Recherche avec préférences utilisateur
prefs = SearchPreferences(
preferred_type=ProductType.DIGITAL, # Filtre doux : relègue les Physical
max_price=50.0, # Filtre dur : exclut > 50€
min_rating=4.0, # Filtre dur : exclut < 4★
user_location="France", # Bonus +15% si même zone
)
results, status = engine.search("cuisine", prefs=prefs, fuzzy=True, max_dist=1)
# Ajout manuel d'un produit
from tagsearch.models import ProductMeta, ProductType
meta = ProductMeta(
name="Casque VR Pro",
product_type=ProductType.PHYSICAL,
niche="gaming",
price=299.0,
location="France",
avg_rating=4.7,
review_count=89,
tags=["casque", "vr", "gaming", "tech"],
)
engine.add_product(11, meta)
API
SearchEngine.search(query, prefs, fuzzy, max_dist, top_k)
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
query |
str |
— | Requête (normalisée en interne) |
prefs |
SearchPreferences |
None |
Préférences de re-ranking |
fuzzy |
bool |
True |
Recherche floue (Levenshtein + pruning) |
max_dist |
int |
1 |
Distance de Levenshtein max |
top_k |
int |
10 |
Nombre de résultats |
Retourne (list[dict], status) où chaque dict contient : id, name, type, niche, price, rating, reviews, score.
SearchPreferences
| Champ | Type | Effet |
|---|---|---|
preferred_type |
ProductType | None |
Filtre doux : ×0.1 si mismatch |
preferred_niche |
str | None |
Boost ×1.2 si match |
max_price |
float | None |
Filtre dur : exclusion |
min_price |
float | None |
Filtre dur : exclusion |
user_location |
str | None |
Bonus ×1.15 si match |
min_rating |
float |
Filtre dur : exclusion (défaut 0.0) |
Formule de scoring
score = bm25_norm × quality_mult × type_factor × niche_boost × proximity × price_factor
bm25_norm=max(min(bm25_raw / 10.0, 1.0), 0.05)quality_mult=(bayesian_rating / 5.0) ** 1.5bayesian_rating=(count × rating + 3.5 × 10) / (count + 10)
Tests
python -m pytest tests/ -v
python -m pytest tests/ -v --tb=short # affichage compact
19 tests, organisés en 4 sections :
TestBM25Components— composants IDF/TF isolésTestScoringDimensions— TC01 à TC05 cross-langageTestCrossLanguageFixtures— scores de référence stablesTestRobustness— gestion d'erreurs exhaustive
Benchmark
| Opération | Complexité | Temps typique (10k tags) |
|---|---|---|
| Autocomplete | O(L) | < 0.1 ms |
| Fuzzy search (max_dist=1) | O(L × ~5% nœuds) | < 1 ms |
| Scoring 100 candidats | O(n) | < 0.5 ms |
| Cache HIT | O(1) | < 0.01 ms |
L = longueur du préfixe/requête
Metadata
Release files for tagsearch 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| tagsearch-1.0.1.tar.gz | 24.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tagsearch-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 42.5 kB
Security for tagsearch 1.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for tagsearch-1.0.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.