Enhance README and setup_weaviate.py to clarify tokenization settings for the ProductProfile collection. Added warnings for tokenization drift and updated usage instructions for collection recreation after embedding or tokenization changes.
This commit is contained in:
parent
68f39cfe95
commit
4eec89aa9d
@ -50,7 +50,9 @@ The pipeline is **idempotent**: a hash manifest (`.processed_manifest.json`) tra
|
|||||||
python setup_weaviate.py
|
python setup_weaviate.py
|
||||||
```
|
```
|
||||||
|
|
||||||
The `ProductProfile` collection is configured to embed `situation_fit_summary` with `gemini-embedding-001` and the `RETRIEVAL_DOCUMENT` task type. If you change embedding settings on an existing database, recreate the collection:
|
The `ProductProfile` collection is configured to embed `situation_fit_summary` with `gemini-embedding-001` and the `RETRIEVAL_DOCUMENT` task type. `product_id` uses `tokenization: field` so filters such as `contains_any` match whole IDs (underscores included) rather than ID fragments.
|
||||||
|
|
||||||
|
Tokenization and embedding settings cannot be changed in place. After changing them, recreate the collection **and** re-ingest with `--force`. Recreating without `--force` leaves Weaviate empty because the hash manifest would skip unchanged files:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python setup_weaviate.py --recreate
|
python setup_weaviate.py --recreate
|
||||||
|
|||||||
@ -7,7 +7,7 @@ Uses Google AI Studio (Gemini API) with:
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
python setup_weaviate.py # create collection if it does not exist
|
python setup_weaviate.py # create collection if it does not exist
|
||||||
python setup_weaviate.py --recreate # delete and recreate (required after embedding config changes)
|
python setup_weaviate.py --recreate # delete and recreate (required after embedding or tokenization changes)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@ -30,7 +30,7 @@ except ModuleNotFoundError:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from weaviate.classes.config import Configure, DataType, Property
|
from weaviate.classes.config import Configure, DataType, Property, Tokenization
|
||||||
|
|
||||||
COLLECTION_NAME = "ProductProfile"
|
COLLECTION_NAME = "ProductProfile"
|
||||||
EMBEDDING_MODEL = "gemini-embedding-001"
|
EMBEDDING_MODEL = "gemini-embedding-001"
|
||||||
@ -62,6 +62,37 @@ def connect_weaviate(cfg: Dict[str, str]) -> weaviate.WeaviateClient:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _tokenization_name(value: object) -> str:
|
||||||
|
"""Normalize a Weaviate tokenization enum or string to a lowercase name."""
|
||||||
|
raw = getattr(value, "value", value)
|
||||||
|
return str(raw).split(".")[-1].lower()
|
||||||
|
|
||||||
|
|
||||||
|
def _warn_if_product_id_tokenization_drift(client: weaviate.WeaviateClient) -> None:
|
||||||
|
"""Warn when an existing collection still tokenizes product_id as words."""
|
||||||
|
collection = client.collections.get(COLLECTION_NAME)
|
||||||
|
config = collection.config.get()
|
||||||
|
actual = None
|
||||||
|
for prop in config.properties:
|
||||||
|
if prop.name == "product_id":
|
||||||
|
actual = getattr(prop, "tokenization", None)
|
||||||
|
break
|
||||||
|
|
||||||
|
if actual is not None and _tokenization_name(actual) == _tokenization_name(Tokenization.FIELD):
|
||||||
|
return
|
||||||
|
|
||||||
|
actual_label = _tokenization_name(actual) if actual is not None else "missing"
|
||||||
|
print(
|
||||||
|
f"[WARN] Collection '{COLLECTION_NAME}' product_id tokenization is '{actual_label}'; "
|
||||||
|
f"expected '{_tokenization_name(Tokenization.FIELD)}'. "
|
||||||
|
"Word tokenization splits underscored IDs, so contains_any filters can match unrelated products. "
|
||||||
|
"Tokenization cannot be changed in place. Recreate and re-ingest:\n"
|
||||||
|
" python setup_weaviate.py --recreate\n"
|
||||||
|
" python ingest.py --force",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def ensure_product_profile_collection(
|
def ensure_product_profile_collection(
|
||||||
client: weaviate.WeaviateClient,
|
client: weaviate.WeaviateClient,
|
||||||
*,
|
*,
|
||||||
@ -76,6 +107,7 @@ def ensure_product_profile_collection(
|
|||||||
if recreate:
|
if recreate:
|
||||||
client.collections.delete(COLLECTION_NAME)
|
client.collections.delete(COLLECTION_NAME)
|
||||||
else:
|
else:
|
||||||
|
_warn_if_product_id_tokenization_drift(client)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
client.collections.create(
|
client.collections.create(
|
||||||
@ -86,6 +118,7 @@ def ensure_product_profile_collection(
|
|||||||
data_type=DataType.TEXT,
|
data_type=DataType.TEXT,
|
||||||
skip_vectorization=True,
|
skip_vectorization=True,
|
||||||
index_filterable=True,
|
index_filterable=True,
|
||||||
|
tokenization=Tokenization.FIELD,
|
||||||
),
|
),
|
||||||
Property(
|
Property(
|
||||||
name="product_name",
|
name="product_name",
|
||||||
@ -115,7 +148,7 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--recreate",
|
"--recreate",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Delete and recreate the collection (use after changing embedding settings).",
|
help="Delete and recreate the collection (use after changing embedding or tokenization settings).",
|
||||||
)
|
)
|
||||||
return parser.parse_args(argv)
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user