Skip to content

Commit 328e218

Browse files
DOC-4835 Python vector embedding example
1 parent 56778da commit 328e218

File tree

1 file changed

+223
-0
lines changed

1 file changed

+223
-0
lines changed
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
---
2+
categories:
3+
- docs
4+
- develop
5+
- stack
6+
- oss
7+
- rs
8+
- rc
9+
- oss
10+
- kubernetes
11+
- clients
12+
description: Store and query vector embeddings with Redis
13+
linkTitle: Vector embeddings
14+
title: Vector embeddings
15+
weight: 5
16+
---
17+
18+
[Redis Query Engine]({{< relref "/develop/interact/search-and-query" >}})
19+
lets you index vector fields in [hash]({{< relref "/develop/data-types/hashes" >}})
20+
or [JSON]({{< relref "/develop/data-types/json" >}}) objects (see the
21+
[Vectors]({{< relref "/develop/interact/search-and-query/advanced-concepts/vectors" >}})
22+
reference page for more information).
23+
Among other things, vector fields can store *text embeddings*, which are AI-generated vector
24+
representations of the semantic information in pieces of text. The
25+
[vector distance]({{< relref "/develop/interact/search-and-query/advanced-concepts/vectors#distance-metrics" >}})
26+
between two embeddings indicates how similar they are semantically. By comparing the
27+
similarity of an embedding generated from some query text with embeddings stored in hash
28+
or JSON fields, Redis can retrieve documents that closely match the query in terms
29+
of their meaning.
30+
31+
The [RedisVL]({{< relref "/develop/clients/redis-vl" >}}) library provides a
32+
high-level Python API to help you use vector embeddings with Redis Query
33+
Engine. The example below shows how RedisVL can retrieve data
34+
that has a similar meaning to the query text you supply.
35+
36+
## Initialize
37+
38+
Start by importing the required classes:
39+
40+
```python
41+
from redisvl.utils.vectorize.text.huggingface import (
42+
HFTextVectorizer
43+
)
44+
from redisvl.index import SearchIndex
45+
from redisvl.query import VectorQuery
46+
```
47+
48+
The first of these imports is the
49+
[`HFTextVectorizer`](https://docs.redisvl.com/en/stable/api/vectorizer.html#hftextvectorizer)
50+
class, which generates
51+
an embedding from a section sample of text. Here, we create an instance of `HFTextVectorizer`
52+
that uses the
53+
[`all-MiniLM-L6-v2`](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2)
54+
model for the embeddings. This model generates vectors with 384 dimensions, regardless
55+
of the length of the input text, but note that the input is truncated to 256
56+
tokens (see
57+
[Word piece tokenization](https://huggingface.co/learn/nlp-course/en/chapter6/6).
58+
at the [Hugging Face](https://huggingface.co/) docs to learn more about how tokens
59+
are related to the original text).
60+
61+
```python
62+
hf = HFTextVectorizer(model="sentence-transformers/all-MiniLM-L6-v2")
63+
```
64+
65+
## Create the index
66+
67+
RedisVL's
68+
[`SearchIndex`](https://docs.redisvl.com/en/stable/api/searchindex.html#searchindex-api)
69+
class provides the
70+
[`from_dict()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.from_dict)
71+
method, which lets you specify your index schema with a Python dictionary, as shown
72+
below. Another option is
73+
[`from_yaml()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.from_yaml),
74+
which loads the index schema from a [YAML](https://en.wikipedia.org/wiki/YAML) file.
75+
76+
The schema in the example below specifies hash objects for storage and includes
77+
three fields: the text content to index, a
78+
[tag]({{< relref "/develop/interact/search-and-query/advanced-concepts/tags" >}})
79+
field to represent the "genre" of the text, and the embedding vector generated from
80+
the original text content. The attributes of the vector field (specified in the
81+
`attrs` object) specify [HNSW]({{< relref "/develop/interact/search-and-query/advanced-concepts/vectors#hnsw-index" >}}) indexing, the
82+
[L2]({{< relref "/develop/interact/search-and-query/advanced-concepts/vectors#distance-metrics" >}})
83+
vector distance metric, `Float32` values to represent the vector's components,
84+
and 384 dimensions, as required by the `all-MiniLM-L6-v2` embedding model.
85+
86+
```python
87+
index = SearchIndex.from_dict({
88+
"index": {
89+
"name": "vector_idx",
90+
"prefix": "doc",
91+
"storage_type": "hash",
92+
},
93+
"fields": [
94+
{"name": "content", "type": "text"},
95+
{"name": "genre", "type": "tag"},
96+
{
97+
"name": "embedding",
98+
"type": "vector",
99+
"attrs": {
100+
"algorithm": "HNSW",
101+
"dims": 384,
102+
"distance_metric": "l2",
103+
"datatype": "float32",
104+
},
105+
},
106+
],
107+
})
108+
```
109+
110+
When you have created the `SearchIndex` object, you must connect to the Redis
111+
server using the
112+
[`connect()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.connect)
113+
method and then use the
114+
[`create()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.create)
115+
method to actually create the index in the database. The `overwrite` parameter for `create()`
116+
ensures that the index you create replaces any existing index with
117+
the same name. The `drop` parameter deletes any objects that were
118+
indexed by the index you are replacing.
119+
120+
```python
121+
index.connect("redis://localhost:6379")
122+
index.create(overwrite=True, drop=True)
123+
```
124+
125+
## Add data
126+
127+
You can now supply the data objects, which will be indexed automatically
128+
when you add them using the
129+
[`load()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.load)
130+
method. Use the
131+
[`embed()`](https://docs.redisvl.com/en/stable/api/vectorizer.html#redisvl.utils.vectorize.text.huggingface.HFTextVectorizer.embed)
132+
method of the `HFTextVectorizer` instance to create the embedding that represents the `content` field. By default, `embed()` returns a list of `float` values to represent the embedding
133+
vector, but you can also supply the `as_buffer` parameter to encode this list as a
134+
binary string. Use the string representation when you are indexing hash objects
135+
(as we are here), but use the default list of `float` for JSON objects.
136+
137+
```python
138+
hf = HFTextVectorizer(model="sentence-transformers/all-MiniLM-L6-v2")
139+
140+
data = [
141+
{
142+
"content": "That is a very happy person",
143+
"genre": "persons",
144+
"embedding": hf.embed("That is a very happy person", as_buffer=True)
145+
},
146+
{
147+
"content": "That is a happy dog",
148+
"genre": "pets",
149+
"embedding": hf.embed("That is a happy dog", as_buffer=True)
150+
},
151+
{
152+
"content": "Today is a sunny day",
153+
"genre": "weather",
154+
"embedding": hf.embed("Today is a sunny day", as_buffer=True)
155+
}
156+
]
157+
158+
index.load(data)
159+
```
160+
161+
## Run a query
162+
163+
After you have created the index, you are ready to run a query against it.
164+
To do this, you must create another embedding vector from your chosen query
165+
text. Redis calculates the similarity between the query vector and each
166+
embedding vector in the index as it runs the query. It then ranks the
167+
results in order of this numeric similarity value.
168+
169+
Create a
170+
[`VectorQuery`](https://docs.redisvl.com/en/stable/api/query.html#vectorquery)
171+
instance by supplying the embedding vector for your
172+
query text, along with the hash or JSON field to match against and the number
173+
of results you want, as shown in the example below. Then, call the
174+
[`query()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.query)
175+
method of `SearchIndex` with your `VectorQuery` instance to run the query.
176+
177+
```python
178+
query = VectorQuery(
179+
vector=hf.embed("That is a happy person"),
180+
vector_field_name="embedding",
181+
return_fields=["content"],
182+
num_results=3,
183+
)
184+
185+
results = index.query(query)
186+
print(results)
187+
```
188+
189+
The code is now ready to run, but note that it may take a while to complete when
190+
you run it for the first time (which happens because RedisVL must download the
191+
`all-MiniLM-L6-v2` model data before it can
192+
generate the embeddings). When you run the code, it outputs the following results
193+
as a list of dict objects:
194+
195+
```Python
196+
[
197+
{
198+
'id': 'doc:cf3c28e7fdd44753af3080a9a7f8d8e9',
199+
'vector_distance': '0.114169985056',
200+
'content': 'That is a very happy person'
201+
},
202+
{
203+
'id': 'doc:614508f297b644d0be47dde5373bb059',
204+
'vector_distance': '0.610845386982',
205+
'content': 'That is a happy dog'
206+
},
207+
{
208+
'id': 'doc:930a7dfca0d74808baee490d747c9534',
209+
'vector_distance': '1.48624813557',
210+
'content': 'Today is a sunny day'
211+
}
212+
]
213+
```
214+
215+
Note that the results are ordered according to the value of the `vector_distance`
216+
field, with the lowest distance indicating the greatest similarity to the query.
217+
As you would expect, the text *"That is a very happy person"* is the result that is
218+
most similar in meaning to the query text *"That is a happy person"*.
219+
220+
## Learn more
221+
222+
See the [RedisVL documentation](https://docs.redisvl.com/en/stable/index.html)
223+
for more details about its features and examples of how to use them.

0 commit comments

Comments
 (0)