Skip to content

Commit 1c12921

Browse files
DOC-4837 started Jedis vector example
1 parent 097adde commit 1c12921

File tree

3 files changed

+236
-2
lines changed

3 files changed

+236
-2
lines changed

content/develop/clients/jedis/produsage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ categories:
1212
description: Get your Jedis app ready for production
1313
linkTitle: Production usage
1414
title: Production usage
15-
weight: 3
15+
weight: 6
1616
---
1717

1818
The following sections explain how to handle situations that may occur

content/develop/clients/jedis/transpipe.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ categories:
1212
description: Learn how to use Redis pipelines and transactions
1313
linkTitle: Pipelines/transactions
1414
title: Pipelines and transactions
15-
weight: 2
15+
weight: 5
1616
---
1717

1818
Redis lets you send a sequence of commands to the server together in a batch.
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
---
2+
categories:
3+
- docs
4+
- develop
5+
- stack
6+
- oss
7+
- rs
8+
- rc
9+
- oss
10+
- kubernetes
11+
- clients
12+
description: Learn how to index and query vector embeddings with Redis
13+
linkTitle: Index and query vectors
14+
title: Index and query vectors
15+
weight: 3
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+
In the example below, we use the
32+
[`sentence-transformers`](https://pypi.org/project/sentence-transformers/)
33+
library to generate vector embeddings to store and index with
34+
Redis Query Engine.
35+
36+
## Initialize
37+
38+
Install [`redis-py`]({{< relref "/develop/clients/redis-py" >}}) if you
39+
have not already done so. Also, install `sentence-transformers` with the
40+
following command:
41+
42+
```bash
43+
pip install sentence-transformers
44+
```
45+
46+
In a new Python source file, start by importing the required classes:
47+
48+
```python
49+
from sentence_transformers import SentenceTransformer
50+
from redis.commands.search.query import Query
51+
from redis.commands.search.field import TextField, TagField, VectorField
52+
from redis.commands.search.indexDefinition import IndexDefinition, IndexType
53+
54+
import numpy as np
55+
import redis
56+
```
57+
58+
The first of these imports is the
59+
`SentenceTransformer` class, which generates an embedding from a section of text.
60+
Here, we create an instance of `SentenceTransformer` that uses the
61+
[`all-MiniLM-L6-v2`](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2)
62+
model for the embeddings. This model generates vectors with 384 dimensions, regardless
63+
of the length of the input text, but note that the input is truncated to 256
64+
tokens (see
65+
[Word piece tokenization](https://huggingface.co/learn/nlp-course/en/chapter6/6)
66+
at the [Hugging Face](https://huggingface.co/) docs to learn more about the way tokens
67+
are related to the original text).
68+
69+
```python
70+
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
71+
```
72+
73+
## Create the index
74+
75+
Connect to Redis and delete any index previously created with the
76+
name `vector_idx`. (The `dropindex()` call throws an exception if
77+
the index doesn't already exist, which is why you need the
78+
`try: except:` block.)
79+
80+
```python
81+
r = redis.Redis(decode_responses=True)
82+
83+
try:
84+
r.ft("vector_idx").dropindex(True)
85+
except redis.exceptions.ResponseError:
86+
pass
87+
```
88+
89+
Next, we create the index.
90+
The schema in the example below specifies hash objects for storage and includes
91+
three fields: the text content to index, a
92+
[tag]({{< relref "/develop/interact/search-and-query/advanced-concepts/tags" >}})
93+
field to represent the "genre" of the text, and the embedding vector generated from
94+
the original text content. The `embedding` field specifies
95+
[HNSW]({{< relref "/develop/interact/search-and-query/advanced-concepts/vectors#hnsw-index" >}})
96+
indexing, the
97+
[L2]({{< relref "/develop/interact/search-and-query/advanced-concepts/vectors#distance-metrics" >}})
98+
vector distance metric, `Float32` values to represent the vector's components,
99+
and 384 dimensions, as required by the `all-MiniLM-L6-v2` embedding model.
100+
101+
```python
102+
schema = (
103+
TextField("content"),
104+
TagField("genre"),
105+
VectorField("embedding", "HNSW", {
106+
"TYPE": "FLOAT32",
107+
"DIM": 384,
108+
"DISTANCE_METRIC":"L2"
109+
})
110+
)
111+
112+
r.ft("vector_idx").create_index(
113+
schema,
114+
definition=IndexDefinition(
115+
prefix=["doc:"], index_type=IndexType.HASH
116+
)
117+
)
118+
```
119+
120+
## Add data
121+
122+
You can now supply the data objects, which will be indexed automatically
123+
when you add them with [`hset()`]({{< relref "/commands/hset" >}}), as long as
124+
you use the `doc:` prefix specified in the index definition.
125+
126+
Use the `model.encode()` method of `SentenceTransformer`
127+
as shown below to create the embedding that represents the `content` field.
128+
The `astype()` option that follows the `model.encode()` call specifies that
129+
we want a vector of `float32` values. The `tobytes()` option encodes the
130+
vector components together as a single binary string rather than the
131+
default Python list of `float` values.
132+
Use the binary string representation when you are indexing hash objects
133+
(as we are here), but use the default list of `float` for JSON objects.
134+
135+
```python
136+
content = "That is a very happy person"
137+
138+
r.hset("doc:0", mapping={
139+
"content": content,
140+
"genre": "persons",
141+
"embedding": model.encode(content).astype(np.float32).tobytes(),
142+
})
143+
144+
content = "That is a happy dog"
145+
146+
r.hset("doc:1", mapping={
147+
"content": content,
148+
"genre": "pets",
149+
"embedding": model.encode(content).astype(np.float32).tobytes(),
150+
})
151+
152+
content = "Today is a sunny day"
153+
154+
r.hset("doc:2", mapping={
155+
"content": content,
156+
"genre": "weather",
157+
"embedding": model.encode(content).astype(np.float32).tobytes(),
158+
})
159+
```
160+
161+
## Run a query
162+
163+
After you have created the index and added the data, you are ready to run a query.
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+
The code below creates the query embedding using `model.encode()`, as with
170+
the indexing, and passes it as a parameter when the query executes
171+
(see
172+
[Vector search]({{< relref "/develop/interact/search-and-query/query/vector-search" >}})
173+
for more information about using query parameters with embeddings).
174+
175+
```python
176+
q = Query(
177+
"*=>[KNN 3 @embedding $vec AS vector_distance]"
178+
).return_field("score").dialect(2)
179+
180+
query_text = "That is a happy person"
181+
182+
res = r.ft("vector_idx").search(
183+
q, query_params={
184+
"vec": model.encode(query_text).astype(np.float32).tobytes()
185+
}
186+
)
187+
188+
print(res)
189+
```
190+
191+
The code is now ready to run, but note that it may take a while to complete when
192+
you run it for the first time (which happens because RedisVL must download the
193+
`all-MiniLM-L6-v2` model data before it can
194+
generate the embeddings). When you run the code, it outputs the following result
195+
object (slightly formatted here for clarity):
196+
197+
```Python
198+
Result{
199+
3 total,
200+
docs: [
201+
Document {
202+
'id': 'doc:0',
203+
'payload': None,
204+
'vector_distance': '0.114169985056',
205+
'content': 'That is a very happy person'
206+
},
207+
Document {
208+
'id': 'doc:1',
209+
'payload': None,
210+
'vector_distance': '0.610845386982',
211+
'content': 'That is a happy dog'
212+
},
213+
Document {
214+
'id': 'doc:2',
215+
'payload': None,
216+
'vector_distance': '1.48624813557',
217+
'content': 'Today is a sunny day'
218+
}
219+
]
220+
}
221+
```
222+
223+
Note that the results are ordered according to the value of the `vector_distance`
224+
field, with the lowest distance indicating the greatest similarity to the query.
225+
As you would expect, the result for `doc:0` with the content text *"That is a very happy person"*
226+
is the result that is most similar in meaning to the query text
227+
*"That is a happy person"*.
228+
229+
## Learn more
230+
231+
See
232+
[Vector search]({{< relref "/develop/interact/search-and-query/query/vector-search" >}})
233+
for more information about the indexing options, distance metrics, and query format
234+
for vectors.

0 commit comments

Comments
 (0)