Skip to content

Commit 78886dd

Browse files
committed
vector search in nodejs tutorial - added range query
1 parent 41a1150 commit 78886dd

File tree

1 file changed

+137
-32
lines changed

1 file changed

+137
-32
lines changed

docs/howtos/solutions/vector/getting-started-vector/index-getting-started-vector.mdx

Lines changed: 137 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,9 @@ Vectors can also be stored in databases in **binary formats** to save space. In
126126

127127
## Generating vectors
128128

129-
The [Hugging Face Transformers](https://huggingface.co/docs/transformers.js/index) library provides pre-trained models that can be fine-tuned or used out-of-the-box for various NLP (natural language processing) tasks. In our context, we're interested in generating sentence and image embeddings (vector).
129+
In our context, we're interested in generating sentence (product description) and image (product image) embeddings/ vector.There are many AI model repositories (say like GitHub) where pre-trained AI models are stored, maintained, and shared with the public.
130130

131-
:::note
132-
transformers.j library is essentially the JavaScript version of Hugging Face's popular Python library.
133-
:::
134-
135-
### Sentence vector
131+
Let's use one of model from [Hugging Face Model Hub](https://huggingface.co/models) for sentence embeddings and from [TensorFlow Hub](https://tfhub.dev/) for image embeddings for diversity.
136132

137133
:::tip GITHUB CODE
138134

@@ -141,16 +137,31 @@ Below is a command to the clone the source code used in this tutorial
141137
git clone https://github.com/redis-developer/redis-vector-nodejs-solutions.git
142138
:::
143139

140+
### Sentence vector
141+
144142
To obtain sentence embeddings, let's use a hugging face model called [Xenova/all-distilroberta-v1](https://huggingface.co/Xenova/all-distilroberta-v1) which is compatible version of [sentence-transformers/all-distilroberta-v1](https://huggingface.co/sentence-transformers/all-distilroberta-v1) for transformer.js with ONNX weights.
145143

146144
:::note
147145

146+
<u>
147+
[Hugging Face Transformers](https://huggingface.co/docs/transformers.js/index)
148+
</u> is a widely-used open-source library for Natural Language Processing (NLP) tasks.
149+
It provides an accessible and straightforward way to use many state-of-the-art NLP
150+
models
151+
152+
transformers.j library is essentially the JavaScript version of Hugging Face's popular Python library.
153+
154+
:::
155+
156+
:::note
157+
148158
<u>[ONNX (Open Neural Network eXchange)](https://onnx.ai) </u> is an open standard
149159
that defines a common set of operators and a common file format to represent deep
150160
learning models in a wide variety of frameworks, including PyTorch and TensorFlow
161+
151162
:::
152163

153-
Below is a Node.js code sample that showcases how to generate vector embeddings for the any sentence provided:
164+
Below is a Node.js code sample that showcases how to generate vector embeddings for any sentence provided:
154165

155166
```sh
156167
npm install @xenova/transformers
@@ -168,13 +179,15 @@ async function generateSentenceEmbeddings(_sentence): Promise<number[]> {
168179
normalize: true,
169180
});
170181

171-
const embeddings: number[] = Object.values(vectorOutput?.data); //object to array
182+
const embeddings: number[] = Object.values(vectorOutput?.data);
172183
return embeddings;
173184
}
174185

175186
export { generateSentenceEmbeddings };
176187
```
177188
189+
Please find vector output for a sample text
190+
178191
```js title="sample output"
179192
const embeddings = await generateSentenceEmbeddings('I Love Redis !');
180193
console.log(embeddings);
@@ -190,12 +203,9 @@ console.log(embeddings);
190203
191204
### Image vector
192205
193-
:::tip GITHUB CODE
194-
195-
Below is a command to the clone the source code used in this tutorial
206+
To obtain image embeddings, let's use a tensor flow model called [mobilenet](https://github.com/tensorflow/tfjs-models/tree/master/mobilenet)
196207
197-
git clone https://github.com/redis-developer/redis-vector-nodejs-solutions.git
198-
:::
208+
Below is a Node.js code sample that showcases how to generate vector embeddings for any image provided:
199209
200210
```sh
201211
npm i @tensorflow/tfjs @tensorflow/tfjs-node @tensorflow-models/mobilenet jpeg-js
@@ -253,7 +263,7 @@ async function generateImageEmbeddings(imagePath: string) {
253263
We are using <u>[mobilenet model](https://github.com/tensorflow/tfjs-models/tree/master/mobilenet)</u> which is trained only on small <u>[set of image classes](https://github.com/tensorflow/tfjs-examples/blob/master/mobilenet/imagenet_classes.js)</u>. Selecting an image classification model depends on various factors, such as the dataset size, dataset diversity, computational resources, and the specific needs of the application. There are many image classification models like EfficientNet, ResNets, Vision Transformers (ViT)..etc which can be chosen from based on your requirements.
254264
:::
255265
256-
Please find vector details for the sample watch image (11001.jpg)
266+
Please find vector output for a sample watch image
257267
258268
</div>
259269
@@ -288,6 +298,13 @@ console.log(imageEmbeddings);
288298
289299
## Database setup
290300
301+
:::tip GITHUB CODE
302+
303+
Below is a command to the clone the source code used in this tutorial
304+
305+
git clone https://github.com/redis-developer/redis-vector-nodejs-solutions.git
306+
:::
307+
291308
### Sample Data seeding
292309
293310
Let's assume a simplified e-commerce scenario. consider below `products` JSON for vector search demonstration in this tutorial.
@@ -337,14 +354,7 @@ const products = [
337354
];
338355
```
339356
340-
:::tip GITHUB CODE
341-
342-
Below is a command to the clone the source code used in this tutorial
343-
344-
git clone https://github.com/redis-developer/redis-vector-nodejs-solutions.git
345-
:::
346-
347-
Below is the sample code to add `products` data as JSON in Redis along with vectors of product descriptions and product image.
357+
Below is the sample code to add `products` data as JSON in Redis along with vectors of product description and product image.
348358
349359
```js title="src/index.ts"
350360
async function addProductWithEmbeddings(_products) {
@@ -383,7 +393,7 @@ Download <u>[RedisInsight](https://redis.com/redis-enterprise/redis-insight/)</u
383393
384394
### Create vector index
385395
386-
Below implementation shows indexing different field types in Redis including vector fields like productDescriptionEmbeddings and productImageEmbeddings.
396+
JSON fields must be indexed in Redis to perform search on them. Below implementation shows indexing different field types including vector fields like productDescriptionEmbeddings and productImageEmbeddings.
387397
388398
```ts title="src/redis-index.ts"
389399
import {
@@ -512,13 +522,23 @@ HNSW : (Hierarchical Navigable Small World) :
512522
HNSW is a graph-based method for indexing high-dimensional data. For bigger datasets it becomes slower to compare with every single vector in the index, so a probabilistic approach through the HNSW algorithm provides very fast search results (but sacrifices some accuracy)
513523
:::
514524
515-
## What is vector search by KNN?
525+
:::note INITIAL_CAP and BLOCK_SIZE parameters
526+
INITIAL_CAP and BLOCK_SIZE are configuration parameters related to how vectors are stored and indexed.
527+
528+
INITIAL_CAP defines the initial capacity of the vector index. It helps in pre-allocating space for the index.
529+
530+
BLOCK_SIZE defines the size of each block of the vector index. As more vectors are added, Redis will allocate memory in chunks, with each chunk being the size of the BLOCK_SIZE. It helps in optimizing the memory allocations during index growth.
531+
:::
532+
533+
## What is vector KNN query?
516534
517535
KNN, or k-Nearest Neighbors, is an algorithm used in both classification and regression tasks, but when referring to "KNN Search," we're typically discussing the task of finding the "k" points in a dataset that are closest (most similar) to a given query point. In the context of vector search, this means identifying the "k" vectors in our database that are most similar to a given query vector, usually based on some distance metric like cosine similarity or Euclidean distance.
518536
519-
Redis provides support for vector search, allowing you to index and then search for vectors [using the KNN approach](https://redis.io/docs/stack/search/reference/vectors/#pure-knn-queries).
537+
### KNN query with Redis
538+
539+
Redis allows you to index and then search for vectors [using the KNN approach](https://redis.io/docs/stack/search/reference/vectors/#pure-knn-queries).
520540
521-
### Vector KNN query with Redis
541+
Below is a Node.js code sample that showcases how to perform a KNN query for any search term provided:
522542
523543
```ts title="src/knn-query.ts"
524544
const float32Buffer = (arr) => {
@@ -573,15 +593,16 @@ const queryProductDescriptionEmbeddingsByKNN = async (
573593
};
574594
```
575595
596+
Please find output for a KNN query in Redis **(Lower score/distance in output indicates higher similarity)**
597+
576598
```js title="sample output"
577599
const result = await queryProductDescriptionEmbeddingsByKNN(
578-
'Puma watch with cat',
579-
3,
600+
'Puma watch with cat', //search term
601+
3, //max no of results expected
580602
);
581603
console.log(JSON.stringify(result, null, 4));
582604

583605
/*
584-
(Lower score/distance indicates higher similarity)
585606
{
586607
"total": 3,
587608
"documents": [
@@ -617,8 +638,92 @@ console.log(JSON.stringify(result, null, 4));
617638
*/
618639
```
619640
620-
- [hybrid-knn-queries](https://redis.io/docs/interact/search-and-query/search/vectors/#hybrid-knn-queries)
641+
Note : Can combine KNN query with regular Redis search feature using [hybrid knn queries](https://redis.io/docs/interact/search-and-query/search/vectors/#hybrid-knn-queries)
642+
643+
## What is vector range query?
644+
645+
Range queries retrieve data that falls within a specified range of values.
646+
For vectors, a "range query" typically refers to retrieving all vectors within a certain distance of a target vector. The "range" in this context is a radius in the vector space.
647+
648+
### Range query with Redis
649+
650+
Below is a Node.js code sample that showcases how to perform a vector range query for any radius (distance) range provided:
651+
652+
```js title="src/range-query.ts"
653+
const queryProductDescriptionEmbeddingsByRange = async (_searchTxt, _range) => {
654+
/* sample raw query
655+
656+
FT.SEARCH idx:products
657+
"@productDescriptionEmbeddings:[VECTOR_RANGE $searchRange $searchBlob]=>{$YIELD_DISTANCE_AS: score}"
658+
RETURN 4 score brandName productDisplayName imageURL
659+
SORTBY score
660+
PARAMS 4 searchRange 0.685 searchBlob "A=\xe1\xbb\x8a\xad\x...."
661+
DIALECT 2
662+
*/
663+
664+
console.log(`queryProductDescriptionEmbeddingsByRange started`);
665+
let results = {};
666+
if (_searchTxt) {
667+
_range = _range ?? 1.0;
668+
669+
const nodeRedisClient = getNodeRedisClient();
670+
671+
const searchTxtVectorArr = await generateSentenceEmbeddings(_searchTxt);
621672

622-
## What is vector search by range ?
673+
const searchQuery =
674+
'@productDescriptionEmbeddings:[VECTOR_RANGE $searchRange $searchBlob]=>{$YIELD_DISTANCE_AS: score}';
623675

624-
### Vector range query with Redis
676+
results = await nodeRedisClient.ft.search(PRODUCTS_INDEX_KEY, searchQuery, {
677+
PARAMS: {
678+
searchBlob: float32Buffer(searchTxtVectorArr),
679+
searchRange: _range,
680+
},
681+
RETURN: ['score', 'brandName', 'productDisplayName', 'imageURL'],
682+
SORTBY: {
683+
BY: 'score',
684+
// DIRECTION: "DESC"
685+
},
686+
DIALECT: 2,
687+
});
688+
} else {
689+
throw 'Search text cannot be empty';
690+
}
691+
692+
return results;
693+
};
694+
```
695+
696+
Please find output for a range query in Redis
697+
698+
```js title="sample output"
699+
const result2 = await queryProductDescriptionEmbeddingsByRange(
700+
'Puma watch with cat', //search term
701+
1.0, //with in score or distance
702+
);
703+
console.log(JSON.stringify(result2, null, 4));
704+
/*
705+
{
706+
"total": 2,
707+
"documents": [
708+
{
709+
"id": "products:1",
710+
"value": {
711+
"score": "0.762174725533",
712+
"brandName": "Puma",
713+
"productDisplayName": "Puma Men Race Black Watch",
714+
"imageURL": "images/11002.jpg"
715+
}
716+
},
717+
{
718+
"id": "products:2",
719+
"value": {
720+
"score": "0.825711071491",
721+
"brandName": "Puma",
722+
"productDisplayName": "Puma Men Top Fluctuation Red Black Watches",
723+
"imageURL": "images/11001.jpg"
724+
}
725+
}
726+
]
727+
}
728+
*/
729+
```

0 commit comments

Comments
 (0)