Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
305 changes: 305 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -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()` |
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading