Skip to content

Commit

Permalink
[Vectorize] Update Vectorize Dev Docs according to V2 Spec (#16409)
Browse files Browse the repository at this point in the history
* VS-273: Update Vectorize Dev Docs according to V2 Spec

* Update src/content/docs/vectorize/best-practices/query-vectors.mdx

* Update src/content/docs/vectorize/best-practices/query-vectors.mdx

* Update src/content/docs/vectorize/reference/metadata-filtering.mdx

* Update src/content/docs/vectorize/best-practices/query-vectors.mdx

* Update src/content/docs/vectorize/best-practices/query-vectors.mdx

* Update src/content/docs/vectorize/reference/transition-vectorize-legacy.mdx

Co-authored-by: Kody Jackson <kody@cloudflare.com>

* Update src/content/docs/vectorize/best-practices/create-indexes.mdx

Co-authored-by: Kody Jackson <kody@cloudflare.com>

---------

Co-authored-by: Yevgen Safronov <yevgen@cloudflare.com>
Co-authored-by: Kody Jackson <kody@cloudflare.com>
  • Loading branch information
3 people committed Aug 23, 2024
1 parent 59df5fa commit c3ae255
Show file tree
Hide file tree
Showing 11 changed files with 458 additions and 192 deletions.
38 changes: 33 additions & 5 deletions src/content/docs/vectorize/best-practices/create-indexes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,7 @@ The configuration of an index cannot be changed after creation.

<Render file="vectorize-wrangler-version" />

:::note[Using Vectorize v1?]

Please use the 'wrangler vectorize --deprecated-v1' flag to create, get, list, delete and insert vectors into legacy Vectorize v1 indexes.

:::
<Render file="vectorize-legacy" />

To create an index with `wrangler`:

Expand All @@ -41,6 +37,38 @@ To create an index that can accept vector embeddings from Worker's AI's [`@cf/ba
npx wrangler vectorize create your-index-name --dimensions=768 --metric=cosine
```

### HTTP API

Vectorize also supports creating indexes via [REST API](/api/operations/vectorize-create-vectorize-index).

For example, to create an index directly from a Python script:

```py
import requests

url = "https://api.cloudflare.com/client/v4/accounts/{}/vectorize/v2/indexes".format("your-account-id")

headers = {
"Authorization": "Bearer <your-api-token>"
}

body = {
"name": "demo-index"
"description": "some index description",
"config": {
"dimensions": 1024,
"metric": "euclidean"
},
}

resp = requests.post(url, headers=headers, json=body)

print('Status Code:', resp.status_code)
print('Response JSON:', resp.json())
```

This script should print the response with a status code `201`, along with a JSON response body indicating the creation of an index with the provided configuration.

## Dimensions

Dimensions are determined from the output size of the machine learning (ML) model used to generate them, and are a function of how the model encodes and describes features into a vector embedding.
Expand Down
30 changes: 20 additions & 10 deletions src/content/docs/vectorize/best-practices/insert-vectors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ import { Render } from "~/components";

Vectorize indexes allow you to insert vectors at any point: Vectorize will optimize the index behind the scenes to ensure that vector search remains efficient, even as new vectors are added or existing vectors updated.

:::note[Insert vs Upsert]

If the same vector id is _inserted_ twice in a Vectorize index, the index would reflect the vector that was added first.

If the same vector id is _upserted_ twice in a Vectorize index, the index would reflect the vector that was added second.

Use the upsert operation if you want to overwrite the vector value for a vector id that already exists in an index.

:::

## Supported vector formats

Vectorize supports vectors in three formats:
Expand All @@ -34,7 +44,7 @@ Metadata can be used to:
For example, a vector embedding representing an image could include the path to the [R2 object](/r2/) it was generated from, the format, and a category lookup:

```ts
{ id: '1', values: [32.4, 74.1, 3.2], metadata: { path: 'r2://bucket-name/path/to/image.png', format: 'png', category: 'profile_image' } }
{ id: '1', values: [32.4, 74.1, 3.2, ...], metadata: { path: 'r2://bucket-name/path/to/image.png', format: 'png', category: 'profile_image' } }
```

## Namespaces
Expand All @@ -43,9 +53,9 @@ Namespaces provide a way to segment the vectors within your index. For example,

To associate vectors with a namespace, you can optionally provide a `namespace: string` value when performing an insert or upsert operation. When querying, you can pass the namespace to search within as an optional parameter to your query.

A namespace can be up to 63 characters (bytes) in length and you can have up to 1,000 namespaces per index. Refer to the [Limits](/vectorize/platform/limits/) documentation for more details.
A namespace can be up to 64 characters (bytes) in length and you can have up to 1,000 namespaces per index. Refer to the [Limits](/vectorize/platform/limits/) documentation for more details.

When a namespace is provided, only vectors within that namespace are used for the search. Namespace filtering is applied before vector search, not after.
When a namespace is specified in a query operation, only vectors within that namespace are used for the search. Namespace filtering is applied before vector search, not after.

To insert vectors with a namespace:

Expand All @@ -56,17 +66,17 @@ To insert vectors with a namespace:
const sampleVectors: Array<VectorizeVector> = [
{
id: "1",
values: [32.4, 74.1, 3.2],
values: [32.4, 74.1, 3.2, ...],
namespace: "text",
},
{
id: "2",
values: [15.1, 19.2, 15.8],
values: [15.1, 19.2, 15.8, ...],
namespace: "images",
},
{
id: "3",
values: [0.16, 1.2, 3.8],
values: [0.16, 1.2, 3.8, ...],
namespace: "pdfs",
},
];
Expand Down Expand Up @@ -97,17 +107,17 @@ Use the `insert()` and `upsert()` methods available on an index from within a Cl
const sampleVectors: Array<VectorizeVector> = [
{
id: "1",
values: [32.4, 74.1, 3.2],
values: [32.4, 74.1, 3.2, ...],
metadata: { url: "/products/sku/13913913" },
},
{
id: "2",
values: [15.1, 19.2, 15.8],
values: [15.1, 19.2, 15.8, ...],
metadata: { url: "/products/sku/10148191" },
},
{
id: "3",
values: [0.16, 1.2, 3.8],
values: [0.16, 1.2, 3.8, ...],
metadata: { url: "/products/sku/97913813" },
},
];
Expand Down Expand Up @@ -154,7 +164,7 @@ For example, to insert embeddings in [NDJSON format](#workers-api) directly from
```py
import requests

url = "https://api.cloudflare.com/client/v4/accounts/{}/vectorize/indexes/{}/insert".format("your-account-id", "index-name")
url = "https://api.cloudflare.com/client/v4/accounts/{}/vectorize/v2/indexes/{}/insert".format("your-account-id", "index-name")

headers = {
"Authorization": "Bearer <your-api-token>"
Expand Down
77 changes: 40 additions & 37 deletions src/content/docs/vectorize/best-practices/query-vectors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ title: Query vectors
pcx_content_type: concept
sidebar:
order: 5

---

Querying an index, or vector search, enables you to search an index by providing an input vector and returning the nearest vectors based on the [configured distance metric](/vectorize/best-practices/create-indexes/#distance-metrics).
Expand All @@ -17,52 +16,56 @@ To pass a vector as a query to an index, use the `query()` method on the index i
A query vector is either an array of JavaScript numbers, 32-bit floating point or 64-bit floating point numbers: `number[]`, `Float32Array`, or `Float64Array`. Unlike when [inserting vectors](/vectorize/best-practices/insert-vectors/), a query vector does not need an ID or metadata.

```ts
let queryVector = [54.8, 5.5, 3.1];
// query vector dimensions must match the Vectorize index dimension being queried
let queryVector = [54.8, 5.5, 3.1, ...];
let matches = await env.YOUR_INDEX.query(queryVector);
```

This would return a set of matches resembling the following, based on a `cosine` distance metric:
This would return a set of matches resembling the following, based on the distance metric configured for the Vectorize index. Example response with `cosine` distance metric:

```json
{
"matches": {
"count": 3,
"matches": [
{ "score": 0.999909486, "id": "5" },
{ "score": 0.789848214, "id": "4" },
{ "score": 0.720476967, "id": "4444" }
]
}
"matches": {
"count": 5,
"matches": [
{ "score": 0.999909486, "id": "5" },
{ "score": 0.789848214, "id": "4" },
{ "score": 0.720476967, "id": "4444" },
{ "score": 0.463884663, "id": "6" },
{ "score": 0.378282232, "id": "1" }
]
}
}
```

You can optionally change the number of results returned and/or whether results should include metadata and values:

```ts
let queryVector = [54.8, 5.5, 3.1];
// topK defaults to 3; returnValues defaults to false; returnMetadata defaults to false
// query vector dimensions must match the Vectorize index dimension being queried
let queryVector = [54.8, 5.5, 3.1, ...];
// topK defaults to 5; returnValues defaults to false; returnMetadata defaults to "none"
let matches = await env.YOUR_INDEX.query(queryVector, {
topK: 1,
returnValues: true,
returnMetadata: true,
topK: 1,
returnValues: true,
returnMetadata: "all",
});
```

This would return a set of matches resembling the following, based on a `cosine` distance metric:
This would return a set of matches resembling the following, based on the distance metric configured for the Vectorize index. Example response with `cosine` distance metric:

```json
{
"matches": {
"count": 1,
"matches": [
{
"score": 0.999909486,
"id": "5",
"values": [58.79999923706055, 6.699999809265137, 3.4000000953674316],
"metadata": { "url": "/products/sku/55519183" }
}
]
}
"matches": {
"count": 1,
"matches": [
{
"score": 0.999909486,
"id": "5",
"values": [58.79999923706055, 6.699999809265137, 3.4000000953674316, ...],
"metadata": { "url": "/products/sku/55519183" }
}
]
}
}
```

Expand All @@ -74,16 +77,16 @@ If you are generating embeddings from a [Workers AI](/workers-ai/models/#text-em

```ts
interface EmbeddingResponse {
shape: number[];
data: number[][];
shape: number[];
data: number[][];
}

let userQuery = "a query from a user or service";
const queryVector: EmbeddingResponse = await env.AI.run(
"@cf/baai/bge-base-en-v1.5",
{
text: [userQuery],
}
"@cf/baai/bge-base-en-v1.5",
{
text: [userQuery],
},
);
```

Expand All @@ -107,15 +110,15 @@ const openai = new OpenAI({ apiKey: env.YOUR_OPENAPI_KEY });
let userQuery = "a query from a user or service";

let embeddingResponse = await openai.embeddings.create({
input: userQuery,
model: "text-embedding-ada-002",
input: userQuery,
model: "text-embedding-ada-002",
});
```

Similar to Workers AI, you will need to provide the vector embedding itself (`.embedding[0]`) and not the `EmbeddingResponse` wrapper when querying a Vectorize index:

```ts
let matches = await env.TEXT_EMBEDDINGS.query(embeddingResponse.embedding[0], {
topK: 1,
topK: 1,
});
```
36 changes: 21 additions & 15 deletions src/content/docs/vectorize/get-started/embeddings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,7 @@ To create your first Vectorize index, change into the directory you just created
cd embeddings-tutorial
```

:::note[Using Vectorize v1?]

Please use the 'wrangler vectorize --deprecated-v1' flag to create, get, list, delete and insert vectors into legacy Vectorize v1 indexes.

:::
<Render file="vectorize-legacy" />

To create an index, use the `wrangler vectorize create` command and provide a name for the index. A good index name is:

Expand All @@ -103,7 +99,7 @@ npx wrangler vectorize create embeddings-index --dimensions=768 --metric=cosine
✅ Successfully created index 'embeddings-index'

[[vectorize]]
binding = "VECTORIZE_INDEX" # available in your Worker on env.VECTORIZE_INDEX
binding = "VECTORIZE" # available in your Worker on env.VECTORIZE
index_name = "embeddings-index"
```

Expand All @@ -117,13 +113,13 @@ To bind your index to your Worker, add the following to the end of your `wrangle

```toml
[[vectorize]]
binding = "VECTORIZE_INDEX" # available in your Worker on env.VECTORIZE_INDEX
binding = "VECTORIZE" # available in your Worker on env.VECTORIZE
index_name = "embeddings-index"
```

Specifically:

- The value (string) you set for `<BINDING_NAME>` will be used to reference this database in your Worker. In this tutorial, name your binding `VECTORIZE_INDEX`.
- The value (string) you set for `<BINDING_NAME>` will be used to reference this database in your Worker. In this tutorial, name your binding `VECTORIZE`.
- The binding must be [a valid JavaScript variable name](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#variables). For example, `binding = "MY_INDEX"` or `binding = "PROD_SEARCH_INDEX"` would both be valid names for the binding.
- Your binding is available in your Worker at `env.<BINDING_NAME>` and the Vectorize [client API](/vectorize/reference/client-api/) is exposed on this binding for use within your Workers application.

Expand All @@ -135,7 +131,7 @@ From within the `embeddings-tutorial` directory, open your `wrangler.toml` file

```toml
[[vectorize]]
binding = "VECTORIZE_INDEX" # available in your Worker on env.VECTORIZE_INDEX
binding = "VECTORIZE" # available in your Worker on env.VECTORIZE
index_name = "embeddings-index"

[ai]
Expand All @@ -148,11 +144,11 @@ With Workers AI ready, you can write code in your Worker.

To write code in your Worker, go to your `embeddings-tutorial` Worker and open the `src/index.ts` file. The `index.ts` file is where you configure your Worker's interactions with your Vectorize index.

Clear the content of `index.ts`. Paste the following code snippet into your `index.ts` file. On the `env` parameter, replace `<BINDING_NAME>` with `VECTORIZE_INDEX`:
Clear the content of `index.ts`. Paste the following code snippet into your `index.ts` file. On the `env` parameter, replace `<BINDING_NAME>` with `VECTORIZE`:

```typescript
export interface Env {
VECTORIZE_INDEX: VectorizeIndex;
VECTORIZE: Vectorize;
AI: Ai;
}
interface EmbeddingResponse {
Expand Down Expand Up @@ -195,7 +191,7 @@ export default {
id++;
});

let inserted = await env.VECTORIZE_INDEX.upsert(vectors);
let inserted = await env.VECTORIZE.upsert(vectors);
return Response.json(inserted);
}

Expand All @@ -208,12 +204,12 @@ export default {
},
);

let matches = await env.VECTORIZE_INDEX.query(queryVector.data[0], {
let matches = await env.VECTORIZE.query(queryVector.data[0], {
topK: 1,
});
return Response.json({
// Expect a vector ID. 1 to be your top match with a score of
// ~0.896888444
// ~0.89693683
// This tutorial uses a cosine distance metric, where the closer to one,
// the more similar.
matches: matches,
Expand Down Expand Up @@ -252,7 +248,17 @@ With the URL for your deployed Worker (for example,`https://embeddings-tutorial.
This should return the following JSON:

```json
{ "matches": { "count": 1, "matches": [{ "score": 0.896888444, "id": "1" }] } }
{
"matches": {
"count": 1,
"matches": [
{
"id": "1",
"score": 0.89693683
}
]
}
}
```

Extend this example by:
Expand Down
Loading

0 comments on commit c3ae255

Please sign in to comment.