- 
                Notifications
    
You must be signed in to change notification settings  - Fork 270
 
DOC-4835 Python vector embedding example #1159
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
          
     Merged
      
      
    
  
     Merged
                    Changes from 1 commit
      Commits
    
    
            Show all changes
          
          
            3 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      
    File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,223 @@ | ||
| --- | ||
| categories: | ||
| - docs | ||
| - develop | ||
| - stack | ||
| - oss | ||
| - rs | ||
| - rc | ||
| - oss | ||
| - kubernetes | ||
| - clients | ||
| description: Store and query vector embeddings with Redis | ||
| linkTitle: Vector embeddings | ||
| title: Vector embeddings | ||
| weight: 5 | ||
| --- | ||
| 
     | 
||
| [Redis Query Engine]({{< relref "/develop/interact/search-and-query" >}}) | ||
| lets you index vector fields in [hash]({{< relref "/develop/data-types/hashes" >}}) | ||
| or [JSON]({{< relref "/develop/data-types/json" >}}) objects (see the | ||
| [Vectors]({{< relref "/develop/interact/search-and-query/advanced-concepts/vectors" >}}) | ||
| reference page for more information). | ||
| Among other things, vector fields can store *text embeddings*, which are AI-generated vector | ||
| representations of the semantic information in pieces of text. The | ||
| [vector distance]({{< relref "/develop/interact/search-and-query/advanced-concepts/vectors#distance-metrics" >}}) | ||
| between two embeddings indicates how similar they are semantically. By comparing the | ||
| similarity of an embedding generated from some query text with embeddings stored in hash | ||
| or JSON fields, Redis can retrieve documents that closely match the query in terms | ||
| of their meaning. | ||
| 
     | 
||
| The [RedisVL]({{< relref "/develop/clients/redis-vl" >}}) library provides a | ||
| high-level Python API to help you use vector embeddings with Redis Query | ||
| Engine. The example below shows how RedisVL can retrieve data | ||
| that has a similar meaning to the query text you supply. | ||
| 
     | 
||
| ## Initialize | ||
| 
     | 
||
| Start by importing the required classes: | ||
| 
     | 
||
| ```python | ||
| from redisvl.utils.vectorize.text.huggingface import ( | ||
| HFTextVectorizer | ||
| ) | ||
| from redisvl.index import SearchIndex | ||
| from redisvl.query import VectorQuery | ||
| ``` | ||
| 
     | 
||
| The first of these imports is the | ||
| [`HFTextVectorizer`](https://docs.redisvl.com/en/stable/api/vectorizer.html#hftextvectorizer) | ||
| class, which generates | ||
| an embedding from a section sample of text. Here, we create an instance of `HFTextVectorizer` | ||
| that uses the | ||
| [`all-MiniLM-L6-v2`](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2) | ||
| model for the embeddings. This model generates vectors with 384 dimensions, regardless | ||
| of the length of the input text, but note that the input is truncated to 256 | ||
| tokens (see | ||
| [Word piece tokenization](https://huggingface.co/learn/nlp-course/en/chapter6/6). | ||
| at the [Hugging Face](https://huggingface.co/) docs to learn more about how tokens | ||
| are related to the original text). | ||
| 
     | 
||
| ```python | ||
| hf = HFTextVectorizer(model="sentence-transformers/all-MiniLM-L6-v2") | ||
| ``` | ||
| 
     | 
||
| ## Create the index | ||
| 
     | 
||
| RedisVL's | ||
| [`SearchIndex`](https://docs.redisvl.com/en/stable/api/searchindex.html#searchindex-api) | ||
| class provides the | ||
| [`from_dict()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.from_dict) | ||
| method, which lets you specify your index schema with a Python dictionary, as shown | ||
| below. Another option is | ||
| [`from_yaml()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.from_yaml), | ||
| which loads the index schema from a [YAML](https://en.wikipedia.org/wiki/YAML) file. | ||
| 
     | 
||
| The schema in the example below specifies hash objects for storage and includes | ||
| three fields: the text content to index, a | ||
| [tag]({{< relref "/develop/interact/search-and-query/advanced-concepts/tags" >}}) | ||
| field to represent the "genre" of the text, and the embedding vector generated from | ||
| the original text content. The attributes of the vector field (specified in the | ||
| `attrs` object) specify [HNSW]({{< relref "/develop/interact/search-and-query/advanced-concepts/vectors#hnsw-index" >}}) indexing, the | ||
| [L2]({{< relref "/develop/interact/search-and-query/advanced-concepts/vectors#distance-metrics" >}}) | ||
| vector distance metric, `Float32` values to represent the vector's components, | ||
| and 384 dimensions, as required by the `all-MiniLM-L6-v2` embedding model. | ||
| 
     | 
||
| ```python | ||
| index = SearchIndex.from_dict({ | ||
| "index": { | ||
| "name": "vector_idx", | ||
| "prefix": "doc", | ||
| "storage_type": "hash", | ||
| }, | ||
| "fields": [ | ||
| {"name": "content", "type": "text"}, | ||
| {"name": "genre", "type": "tag"}, | ||
| { | ||
| "name": "embedding", | ||
| "type": "vector", | ||
| "attrs": { | ||
| "algorithm": "HNSW", | ||
| "dims": 384, | ||
| "distance_metric": "l2", | ||
| "datatype": "float32", | ||
                
      
                  andy-stark-redis marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| }, | ||
| }, | ||
| ], | ||
| }) | ||
| ``` | ||
| 
     | 
||
| When you have created the `SearchIndex` object, you must connect to the Redis | ||
| server using the | ||
| [`connect()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.connect) | ||
| method and then use the | ||
| [`create()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.create) | ||
| method to actually create the index in the database. The `overwrite` parameter for `create()` | ||
                
      
                  andy-stark-redis marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| ensures that the index you create replaces any existing index with | ||
| the same name. The `drop` parameter deletes any objects that were | ||
| indexed by the index you are replacing. | ||
| 
     | 
||
| ```python | ||
| index.connect("redis://localhost:6379") | ||
| index.create(overwrite=True, drop=True) | ||
| ``` | ||
| 
     | 
||
| ## Add data | ||
| 
     | 
||
| You can now supply the data objects, which will be indexed automatically | ||
| when you add them using the | ||
| [`load()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.load) | ||
| method. Use the | ||
| [`embed()`](https://docs.redisvl.com/en/stable/api/vectorizer.html#redisvl.utils.vectorize.text.huggingface.HFTextVectorizer.embed) | ||
| 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 | ||
| vector, but you can also supply the `as_buffer` parameter to encode this list as a | ||
| binary string. Use the string representation when you are indexing hash objects | ||
| (as we are here), but use the default list of `float` for JSON objects. | ||
| 
     | 
||
| ```python | ||
| hf = HFTextVectorizer(model="sentence-transformers/all-MiniLM-L6-v2") | ||
| 
     | 
||
| data = [ | ||
| { | ||
| "content": "That is a very happy person", | ||
| "genre": "persons", | ||
| "embedding": hf.embed("That is a very happy person", as_buffer=True) | ||
| }, | ||
| { | ||
| "content": "That is a happy dog", | ||
| "genre": "pets", | ||
| "embedding": hf.embed("That is a happy dog", as_buffer=True) | ||
| }, | ||
| { | ||
| "content": "Today is a sunny day", | ||
| "genre": "weather", | ||
| "embedding": hf.embed("Today is a sunny day", as_buffer=True) | ||
| } | ||
| ] | ||
| 
     | 
||
| index.load(data) | ||
| ``` | ||
| 
     | 
||
| ## Run a query | ||
| 
     | 
||
| After you have created the index, you are ready to run a query against it. | ||
| To do this, you must create another embedding vector from your chosen query | ||
| text. Redis calculates the similarity between the query vector and each | ||
| embedding vector in the index as it runs the query. It then ranks the | ||
| results in order of this numeric similarity value. | ||
| 
     | 
||
| Create a | ||
| [`VectorQuery`](https://docs.redisvl.com/en/stable/api/query.html#vectorquery) | ||
| instance by supplying the embedding vector for your | ||
| query text, along with the hash or JSON field to match against and the number | ||
| of results you want, as shown in the example below. Then, call the | ||
| [`query()`](https://docs.redisvl.com/en/stable/api/searchindex.html#redisvl.index.SearchIndex.query) | ||
| method of `SearchIndex` with your `VectorQuery` instance to run the query. | ||
| 
     | 
||
| ```python | ||
| query = VectorQuery( | ||
| vector=hf.embed("That is a happy person"), | ||
| vector_field_name="embedding", | ||
| return_fields=["content"], | ||
| num_results=3, | ||
| ) | ||
| 
     | 
||
| results = index.query(query) | ||
| print(results) | ||
| ``` | ||
| 
     | 
||
| The code is now ready to run, but note that it may take a while to complete when | ||
| you run it for the first time (which happens because RedisVL must download the | ||
| `all-MiniLM-L6-v2` model data before it can | ||
| generate the embeddings). When you run the code, it outputs the following results | ||
| as a list of dict objects: | ||
| 
     | 
||
| ```Python | ||
| [ | ||
| { | ||
| 'id': 'doc:cf3c28e7fdd44753af3080a9a7f8d8e9', | ||
| 'vector_distance': '0.114169985056', | ||
| 'content': 'That is a very happy person' | ||
| }, | ||
| { | ||
| 'id': 'doc:614508f297b644d0be47dde5373bb059', | ||
| 'vector_distance': '0.610845386982', | ||
| 'content': 'That is a happy dog' | ||
| }, | ||
| { | ||
| 'id': 'doc:930a7dfca0d74808baee490d747c9534', | ||
| 'vector_distance': '1.48624813557', | ||
| 'content': 'Today is a sunny day' | ||
| } | ||
| ] | ||
| ``` | ||
| 
     | 
||
| Note that the results are ordered according to the value of the `vector_distance` | ||
| field, with the lowest distance indicating the greatest similarity to the query. | ||
| As you would expect, the text *"That is a very happy person"* is the result that is | ||
| most similar in meaning to the query text *"That is a happy person"*. | ||
| 
     | 
||
| ## Learn more | ||
| 
     | 
||
| See the [RedisVL documentation](https://docs.redisvl.com/en/stable/index.html) | ||
| for more details about its features and examples of how to use them. | ||
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.