From 1323584c9352449dee2ea9338d9e8071f014da62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ha=C5=82as?= Date: Wed, 8 Jul 2026 14:19:47 +0200 Subject: [PATCH] docs: create MIGRATION.md with migration guide for deprecated APIs (closes #68) - Add MIGRATION.md at project root covering: - Index Creation migration (createHnswIndex etc. -> createIndex + ZVecIndexParams) - Statistics migration (stats() -> getStatsStruct()) - Schema Introspection (new getFieldSchema() API) - Collection Options (ZVecCollectionOptions with createWith/openWith) - Query Object Pattern (ZVecVectorQuery + queryVector()) - Reranker in Queries (queryWithReranker()) - Deprecated Schema Methods (addField* -> add*) - Add 'Upgrading from v0.4.x' section to README.md linking to MIGRATION.md - Add CHANGELOG.md entry for DOC-009 --- CHANGELOG.md | 5 + MIGRATION.md | 305 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 12 ++ 3 files changed, 322 insertions(+) create mode 100644 MIGRATION.md diff --git a/CHANGELOG.md b/CHANGELOG.md index b19dc47..d11e50d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **DOC-009: Created MIGRATION.md with migration guide from deprecated APIs** (#68) + - Added `MIGRATION.md` at project root covering: Index Creation (HNSW, Flat, IVF, HNSW-RaBitQ, Vamana), Statistics, Schema Introspection, Collection Options, Query Object Pattern, Reranker in Queries, and Deprecated Schema Methods + - Each section includes BEFORE (old API) and AFTER (new API) code blocks + - Added "Upgrading from v0.4.x" section to README.md linking to MIGRATION.md + - **DOC-004: Added PHPDoc blocks to all constant declarations across ZVec, ZVecSchema, and ZVecDoc** (#63) - Added descriptive PHPDoc blocks before 57 constants in `ZVec.php` (index types, query params, log types/levels, buffer sizes, HNSW defaults, data types, quantize types) - Added PHPDoc blocks before 4 metric type constants in `ZVecSchema.php` (METRIC_L2, METRIC_IP, METRIC_COSINE, METRIC_MIPSL2) diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 0000000..328dcc4 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,305 @@ +# Migration Guide: v0.4.x → v0.5.0 + +This guide helps users of the deprecated v0.4.x APIs migrate to the modern +v0.5.0 APIs. All deprecated methods still work but emit `E_USER_DEPRECATED` +warnings and will be removed in v0.6.0. + +## Index Creation + +The four separate `create*Index()` methods have been replaced by a unified +`createIndex()` + `ZVecIndexParams` pattern. + +### HNSW Index + +```php +// BEFORE (deprecated — removed in v0.6.0): +$collection->createHnswIndex( + 'embedding', + ZVecSchema::METRIC_IP, + 50, // $m + 500, // $efConstruction + 0, // $quantizeType + 0, // $concurrency + false // $useContiguousMemory +); + +// AFTER (recommended): +$collection->createIndex('embedding', ZVecIndexParams::forHnsw( + metricType: ZVecSchema::METRIC_IP, + m: 50, + efConstruction: 500, + quantizeType: ZVec::QUANTIZE_UNDEFINED, + useContiguousMemory: false, +)); +``` + +**Note:** `$concurrency` is no longer part of the index params; use the +`$concurrency` parameter on `createIndex()` directly if needed: +`$collection->createIndex('embedding', $params, concurrency: 4)`. + +### Flat Index + +```php +// BEFORE (deprecated — removed in v0.6.0): +$collection->createFlatIndex( + 'embedding', + ZVecSchema::METRIC_IP, + 0, // $quantizeType + 0 // $concurrency +); + +// AFTER (recommended): +$collection->createIndex('embedding', ZVecIndexParams::forFlat( + metricType: ZVecSchema::METRIC_IP, + quantizeType: ZVec::QUANTIZE_UNDEFINED, +)); +``` + +### IVF Index + +```php +// BEFORE (deprecated — removed in v0.6.0): +$collection->createIvfIndex( + 'embedding', + ZVecSchema::METRIC_IP, + 1024, // $nList + 10, // $nIters + false, // $useSoar + 0, // $quantizeType + 0 // $concurrency +); + +// AFTER (recommended): +$collection->createIndex('embedding', ZVecIndexParams::forIvf( + metricType: ZVecSchema::METRIC_IP, + nList: 1024, + nIters: 10, + useSoar: false, + quantizeType: ZVec::QUANTIZE_UNDEFINED, +)); +``` + +### HNSW-RaBitQ Index + +```php +// BEFORE (deprecated — removed in v0.6.0): +$collection->createHnswRabitqIndex( + 'embedding', + ZVecSchema::METRIC_IP, + 7, // $totalBits + 16, // $numClusters + 50, // $m + 500, // $efConstruction + 0, // $sampleCount + 0 // $concurrency +); + +// AFTER (recommended): +$collection->createIndex('embedding', ZVecIndexParams::forHnswRabitq( + metricType: ZVecSchema::METRIC_IP, + totalBits: 7, + numClusters: 16, + m: 50, + efConstruction: 500, + sampleCount: 0, +)); +``` + +### Vamana (DiskANN) Index + +The old API had no Vamana support. This is new in v0.5.0: + +```php +// NEW (no prior equivalent): +$collection->createIndex('embedding', ZVecIndexParams::forVamana( + metricType: ZVecSchema::METRIC_COSINE, + maxDegree: 64, + searchListSize: 100, + alpha: 1.2, + saturateGraph: false, + useContiguousMemory: false, + useIdMap: false, + quantizeType: ZVec::QUANTIZE_UNDEFINED, +)); +``` + +### Inverted Index + +Inverted indexes are also available via `ZVecIndexParams`: + +```php +// NEW (no prior equivalent): +$collection->createIndex('title', ZVecIndexParams::forInvert( + enableRange: true, + enableWildcard: false, +)); +``` + +The old `createInvertIndex()` method is not deprecated and works alongside +the new API. + +## Statistics + +The old `stats()` method returns a JSON string that needs manual parsing. +The new `getStatsStruct()` returns a typed `ZVecCollectionStats` object. + +```php +// BEFORE: +$json = $collection->stats(); +$data = json_decode($json, true); +echo $data['doc_count']; // int +echo $data['index_count']; // int +echo $data['segment_count']; // int +echo $data['index_completeness']; // float + +// AFTER: +$stats = $collection->getStatsStruct(); +echo $stats->getDocCount(); // int +echo $stats->getIndexCount(); // int +echo $stats->getSegmentCount(); // int +echo $stats->getIndexCompleteness(); // float +echo $stats->getIndexNames(); // string[] +``` + +**Benefits:** Type-safe, no JSON decode needed, IDE autocompletion. + +## Schema Introspection + +`getFieldSchema()` is new in v0.5.0 — no prior equivalent. + +```php +// New API: +$schema = $collection->getFieldSchema('embedding'); +echo $schema->getName(); // "embedding" +echo $schema->getDataType(); // 23 = TYPE_VECTOR_FP32 +echo $schema->getDimension(); // 768 +echo $schema->getMetricType(); // 2 = METRIC_IP +echo $schema->isVectorField(); // true +echo $schema->isSparseVector(); // false +``` + +Also new: `ZVecFieldSchema` exposes `getElementType()` for array fields and +proper nullable detection. + +## Collection Options + +The old `create()` / `open()` methods used flat boolean/integer parameters. +The new `ZVecCollectionOptions` object provides a structured, extensible way +to configure collection creation and opening. + +```php +// BEFORE: +$collection = ZVec::create( + $path, + $schema, + false, // $readOnly + true, // $enableMmap + 67108864 // $maxBufferSize +); + +// AFTER: +$options = new ZVecCollectionOptions( + readOnly: false, + enableMmap: true, + maxBufferSize: 67108864, +); +$collection = ZVec::createWith($path, $schema, $options); + +// Or use factory methods: +$options = ZVecCollectionOptions::defaults(); +$options->setReadOnly(true) + ->setMaxBufferSize(134217728); // 128 MB +$collection = ZVec::openWith($path, $options); +``` + +Factory methods available: +- `ZVecCollectionOptions::readOnly()` — open in read-only mode +- `ZVecCollectionOptions::readWrite()` — explicit read-write mode +- `ZVecCollectionOptions::defaults()` — default settings + +## Query Object Pattern + +The old `query()` method accepted many positional parameters. The new +`ZVecVectorQuery` builder provides a fluent, self-documenting alternative. + +```php +// BEFORE: +$results = $collection->query( + 'embedding', + [0.1, 0.2, 0.3, 0.4], + topk: 10, + includeVector: true, + filter: 'category = "electronics"', + outputFields: ['name', 'price'], + hnswEf: 200, +); + +// AFTER: +$query = new ZVecVectorQuery('embedding', [0.1, 0.2, 0.3, 0.4]); +$query->setTopk(10) + ->setIncludeVector(true) + ->setFilter('category = "electronics"') + ->setOutputFields(['name', 'price']) + ->setHnswParams(ef: 200); + +$results = $collection->queryVector($query); +``` + +The `queryVector()` method accepts the query object directly and returns +the same `ZVecDoc[]`. + +## Reranker in Queries + +The `$reranker` parameter on `query()` is deprecated. Use `queryWithReranker()` +instead for type-safe reranked results. + +```php +// BEFORE (deprecated): +$results = $collection->query( + 'embedding', + [0.1, 0.2, 0.3, 0.4], + topk: 10, + reranker: new ZVecRrfReRanker(topn: 10), +); +// Returns ZVecDoc[]|ZVecRerankedDoc[] — ambiguous type + +// AFTER (recommended): +$reranker = new ZVecRrfReRanker(topn: 10); +$results = $collection->queryWithReranker( + 'embedding', + [0.1, 0.2, 0.3, 0.4], + topk: 10, + reranker: $reranker, +); +// Returns ZVecRerankedDoc[] — always typed +``` + +## Deprecated Schema Methods + +The old `addField*()` prefix methods are deprecated. Use the unprefixed versions. + +```php +// BEFORE (deprecated): +$schema->addFieldBinary('blob'); +$schema->addFieldArrayString('tags'); +$schema->addFieldArrayBool('flags'); + +// AFTER (recommended): +$schema->addBinary('blob'); +$schema->addArrayString('tags'); +$schema->addArrayBool('flags'); +``` + +Full list of renamed methods: + +| Deprecated (old) | Recommended (new) | +|---|---| +| `addFieldBinary()` | `addBinary()` | +| `addFieldArrayString()` | `addArrayString()` | +| `addFieldArrayBool()` | `addArrayBool()` | +| `addFieldArrayInt32()` | `addArrayInt32()` | +| `addFieldArrayInt64()` | `addArrayInt64()` | +| `addFieldArrayUint32()` | `addArrayUint32()` | +| `addFieldArrayUint64()` | `addArrayUint64()` | +| `addFieldArrayFloat()` | `addArrayFloat()` | +| `addFieldArrayDouble()` | `addArrayDouble()` | diff --git a/README.md b/README.md index 8c06108..eb961b8 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,18 @@ php -r 'echo extension_loaded("zvec") ? "zvec extension loaded" : "not loaded";' When the extension is loaded, `require_once 'src/ZVec.php'` is a no-op (guard clause skips the FFI implementation), so existing code works without changes. +## Upgrading from v0.4.x + +See [MIGRATION.md](./MIGRATION.md) for a complete migration guide covering: + +- **Index Creation** — replace `createHnswIndex()`, `createFlatIndex()`, etc. with `createIndex()` + `ZVecIndexParams` +- **Statistics** — replace `stats()` JSON parsing with typed `getStatsStruct()` +- **Schema Introspection** — new `getFieldSchema()` API +- **Collection Options** — use `ZVecCollectionOptions` with `createWith()`/`openWith()` +- **Query Object** — use `ZVecVectorQuery` builder with `queryVector()` +- **Reranker in Queries** — use `queryWithReranker()` instead of `$reranker` param on `query()` +- **Deprecated Schema Methods** — rename `addField*()` to `add*()` (e.g. `addFieldBinary()` → `addBinary()`) + ## Quick Start ```php