| 
 | 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