Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Vectorize] Update Vectorize Dev Docs according to V2 Spec #16409

Merged
merged 8 commits into from
Aug 23, 2024
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.
sejoker marked this conversation as resolved.
Show resolved Hide resolved

## 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 should match the Vectorize index dimension being queried
sejoker marked this conversation as resolved.
Show resolved Hide resolved
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 should match the Vectorize index dimension being queried
sejoker marked this conversation as resolved.
Show resolved Hide resolved
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
Loading