向量相似度(Vector Similarity)

向量(Vectors)(也称为“嵌入(Embeddings)”)表示 AI 模型对文本、图像、音频、视频等非结构化数据的印象(或理解)。向量相似度搜索(VSS)是查找向量数据库中与给定查询向量相似的向量的过程。VSS 的常见用途包括推荐系统、图像和视频搜索、文档检索以及问答系统。

索引创建(Index Creation)

在进行向量搜索之前,首先定义模式并创建索引。

[1]:
import redis
from redis.commands.search.field import TagField, VectorField
from redis.commands.search.indexDefinition import IndexDefinition, IndexType
from redis.commands.search.query import Query

r = redis.Redis(host="localhost", port=6379)

INDEX_NAME = "index"                              # Vector Index Name
DOC_PREFIX = "doc:"                               # RediSearch Key Prefix for the Index

def create_index(vector_dimensions: int):
    try:
        # check to see if index exists
        r.ft(INDEX_NAME).info()
        print("Index already exists!")
    except:
        # schema
        schema = (
            TagField("tag"),                       # Tag Field Name
            VectorField("vector",                  # Vector Field Name
                "FLAT", {                          # Vector Index Type: FLAT or HNSW
                    "TYPE": "FLOAT32",             # FLOAT32 or FLOAT64
                    "DIM": vector_dimensions,      # Number of Vector Dimensions
                    "DISTANCE_METRIC": "COSINE",   # Vector Search Distance Metric
                }
            ),
        )

        # index Definition
        definition = IndexDefinition(prefix=[DOC_PREFIX], index_type=IndexType.HASH)

        # create Index
        r.ft(INDEX_NAME).create_index(fields=schema, definition=definition)

我们将从处理具有 1536 个维度的向量开始。

[2]:
# define vector dimensions
VECTOR_DIMENSIONS = 1536

# create the index
create_index(vector_dimensions=VECTOR_DIMENSIONS)

将向量添加到 Redis

接下来,我们使用 hset 将向量(虚拟数据)添加到 Redis。搜索索引监听键空间通知,并将包括任何以 DOC_PREFIX 为前缀写入的 HASH 对象。

[ ]:
%pip install numpy
[3]:
import numpy as np
[4]:
# instantiate a redis pipeline
pipe = r.pipeline()

# define some dummy data
objects = [
    {"name": "a", "tag": "foo"},
    {"name": "b", "tag": "foo"},
    {"name": "c", "tag": "bar"},
]

# write data
for obj in objects:
    # define key
    key = f"doc:{obj['name']}"
    # create a random "dummy" vector
    obj["vector"] = np.random.rand(VECTOR_DIMENSIONS).astype(np.float32).tobytes()
    # HSET
    pipe.hset(key, mapping=obj)

res = pipe.execute()

搜索(Searching)

您可以使用 .ft(...).search(...) 查询命令执行向量相似性搜索(VSS)查询。要使用 VSS 查询,您必须指定选项 .dialect(2)

Redis 支持两种类型的向量查询:KNN(最近邻)和 Range(范围)。Hybrid 查询可以在这两种设置中工作,结合传统搜索和 VSS 的元素。

KNN 查询

KNN 查询用于根据给定的查询向量查找最相似的前 K 个向量。

[5]:
query = (
    Query("*=>[KNN 2 @vector $vec as score]")
     .sort_by("score")
     .return_fields("id", "score")
     .return_field("vector", decode_field=False) # return the vector field as bytes
     .paging(0, 2)
     .dialect(2)
)

query_params = {
    "vec": np.random.rand(VECTOR_DIMENSIONS).astype(np.float32).tobytes()
}
r.ft(INDEX_NAME).search(query, query_params).docs
[5]:
[Document {'id': 'doc:c', 'payload': None, 'score': '0.251625061035', 'vector': b'\xf8\x1ed?\xbf\t\x90<\xfd\x9b\x10?\xe3\x1b\xed>\xbc\xea%=lp\x1a>\x11hC?\x84 :?\x8d\x7f\xe4>\xfd\xff\x94>n\x9c4?\x0e\x9fy?\xd6\x8a\x97<\xf6\x0b"?Kg\x99>\xc4\xde0>\xa5\r\xb9>\xb0R(>\xd3\x1d\xcd>?\xab\xbb>\x9cx\x0c?\xd7\xa3\x9e>\xad\xee\xf4<\x0c\x93\xf6>aW\x0b?\xd8F0<0\x9e(?\xc5Pn>\x03\xf4\xb0>B\xaay?\xa9~\x7f?Gh\x18>\x15\x8e\xf1>]\xc8\xea>x\xc5\x9c>\xa1\xeb>?\xbb\n-?aDZ?\x92\x9bL<4\xa4\r?\x1d\xe1\xcd>cO\xa3>\'\xed<?\x8a\x15\xf5>vPk?\xa7\xdch?\x02\x14\x8a>\xb6:\x07;O\x139?\x8d$5?^e5?\x06\x10\x89>\x88+\xd2>\xea\xb7\xa4>\xf9\x0e-?\x9c\xbf\xb5>\x81\x8e\x03?\x00\xc43?/\xdb\xfb>\xe8\'e>\xbe\xaa9?\xf2\xe88?\x1b\xa8\x03>\x91\x9fO?%\xb2;?\xb7}w?\xd0/\x08?\x1aD\x1c?\xf9E??\x9bB.?\x96)\x19?\x10a\xda>+\xbfV>\x83\xbd}>\x0bTz>\x82Mz?\xf0EY?:\x99\x19?"\x1ep?\xafX\xcb>*\xa0\x0c>X\xf5\xb9>\x8d\t8?Q\xba\xf4>\x1e\x97x>\xc0Q@?\xd2\x1a\xa6>M\xed\xcf>\x15\x90$>\xb7\x99[?o\x84e?\x8a2P?\x8c\x92^?\'\xe3\xd9>@\x83(?E\x91V?\xad\x1b\xa8>\xf5\xca=?\x0c\x10h?m8\xc0>\xaf\xe4f?\xb9\xdcZ?\xce9\xdb>\x9f|\xc1>^\xa9B>\xc3\xce_>s\x93\xd4<\x96\xd7\x02?\x10\t ?\x07\xb9:>\x9f_\xa4=\xcb\xecK>\xb2\xdes>\x9f\x0b*?ln\x15>\x0c;y?L\xe7a?:\x8fg?Hs\x17?`v\t?\xdf\xe8Q?1Od=4\x1c\xba>\x1b\n8=;\x9f??\xbb\xa5X=kLL=u=4?\xdf\x17<>\x1b\x06\xb5>\x91W\xc5>H\nw?\xc8\x05N?w\xf5\xcf>\xee^Y?\x14\x90\xd1;\xc7b">\xfa\xeb_?y\xbb\x95>\xef\xb66>\xe4Pa?c-/?\x88\x9a\xf2=\xe9\x8b\t?fp\xda>B\xcb\xef=\xd0\x1b\x99>\x0e\xb2f?n\x82~>\xd6e\xcb>\x02\\a?\xcbR\x14?cY[?E\xfc\xe7>0v\x14?\x0c\x1e\x07?`\x1f\xdc=\xb7\x1d\r>v/4?\xaa\xb2\r?\xda\x89\xfa=c>x>\x01\xd2\xad>\x04\xd3\xe6>\xa7E\x9d=\xc0|_?\xcf\x96o?\x89dd?\xbb\xad>?UL\'<\xf4$h<\x9fO\x12?\x86*\xd4>\xef\x8dU?\x02\xc9_=5\xf8.?\xe5\xf8\x11?\x96y\xec>\x18S\xac>BT\xec<\xa4bu?\xa3v-?s\x8eq?\xc8\x99b?u\xf6\xc9=\xca\x9b*?\xb9O)?s\xa9\r?\x8d\xf6\x9d> \xba/?\xe9\x7f\xb7>\xd4}\xc3=C\x99a?\xf5\xf4\x1e=(\xb54?X\xe1_?\xd7\xa7a=\xe12:>\xb1,\xb9>R\x0b\x17;\xe7\xe8\x8a=Ew\x05?\x1a\x0es?\xdc&w?\xe2J`?\xde\x9b\xd7>\xb7\xbf\xb5>\x9d\xbd\xdb>\xb4\x10\x19?\xb10D?L_\xc2>#\x0e\x8e>o\x08\x05>\xab\xec\x10?\xbd6)?\xd5i]?\xd4F\xe4=\x93I\xf3>\xcdc\xd3>\x1f\xb5\x11?\xab\xabW?\xden;?\x96h\xf1<\x8d\xf1#?\xa4sA?\xac\x8d<?\'\xef\xa0>?\x86.> \xf9\t?g\xcc\x93=\xc2\x98I?\xcc\xc0P?\xdd9`?@\'\xfa>\xe4\x1c\xf5>\xaa\xcfn>|\xae\x10?\x1a\x9b\x1e?\x86\x10F?6\xc2\xaf>$L\xf2>\xfb\x0c\x8b>\xbb\xb4\xb7>{K\x98> 1\x1a?\xd8N\x8c=h\x0cx?\xfd\x98\xe2=\xe5\x02,>\x97p\x06?\xb6!\xe1>\x95\xfc\x93>\x8co\xf0>\xa54\xfe>\x94\xe7j?\x0c6\x13?\xba\xe0\xc1>%ll?;\xafW?\xf9\xb9\x9d>\xdd:N?SZ~>:p$?1\x00z>C$\xb9>\x8c\xeaL?\x96|!?.6\xe9>\xf2i\xf2> \x0c(?\xb4|\x80>Yx\x88>\xd2 \xe6>\xe1\x94\x00?\xc0\x88C?\x134\'?Oy\x9f>\xb5\xeaw?\x97X\'?\xa3\x07\x07?\x94.h?B\xf5\xd1>\xd9\xae2>\xbf\x9e,?*w\xa3>\xbe\x8e\x12?ZU>?\x83\xaar?\xbe.\x82>\x0e^^?\x07\xe4\xa2>\x04dZ?#)\x1f?\xbd\x0f\xa0=\xac\x9e\xfe>\xb1\x81B>\x827a?\xcb\xfb\x08?\x04\xca\xa2<7Zd?\xdau9?\xe6Z.?4\x96N?\xf6\xcaw>+\xa64?p\xe3\xae>\xaey\x95>!H\xb7>~!\xbe>\xe1\x0eK>\x98\xdaZ?\xe0\x0b\xbc>\xdd\xc8??\x98\xaf >o\x8d\x7f?\x16\xea\xa3>r\x94F>\xfb\xa5i?n\xf0\xdd>u\x19e>\xb3j\x1e=\xf7S\x0b?\xdaY\x0b?\xbd\x11\x9b>\xa77\xa2>\xcc^\xaf>\xf9a\xa7>\xc2N\x13?\xcbf\x12?\xb4\x1bK>j\xb7L?\x99aS?\xeeyY?\x968\x82=R\x0e#>`\xb9c={\nH?b\xb4\x14>d\x02W?\xde\xd4\\>\xe5\xb6F?>\x96\xac>\xc7`\x91>?\x0e\xad>]\x84\x02?\xac\x14{?(2\xad>\x11\xdd\xf6=\xa0\xb5\xbf>df\xad>\xea\xe1\x04?B\x17:?k\xb8\xb6=|\xbft?\x84\x1f\x05>\xab&??\x156\xc2>`Y\x02>J!\x1f?\xc0\xce\x1a?-V2?\xe8\xfen?\xb58\x1c?\x91\x96\x94>\xa1"\x1e?K\xd5\x04?Gk\xa9>\xf0\xd7\x03?{;l?\x88\xa5!>t\x0e\r>%E\xa8>\n\x1cM?\x8b\xbfN?\xc9\x84\xea>\xdb\xebd?\xe7\xe9G?-t\x9b>\xb8\xc80?\xb7w"?\xdcz1>xT\xf2=\xb7\x12\xa1>\x887\x95>8\x19\xdf>\xa9\xbbY?\x89w\x8d>M\xb4r=\xd1~\x02?\xd1\xd6x?\x0c\xb7\x06?\xc1w\x17>v\xba\xe4>\x11\x16\xec>\x9f\x8a\xc7>r\xf0L?d_>>\x01TS?8\x9f\x0b>RBd="\xc3\xe1;\x9f\xf7\x9c>^\x1cg?\xc5\xee\n?N."?\x9d\x13\x8c=\x9e\x90W>\'\xf0<>&\x86]?\xb6[\xe2>\xf9S5<N\xe0@>\x1f\x1aN>s\xbfL?\xbb\xec=?\xcf\x08C?\\M\xa8>\xc7\xcf\xe3=\x84\xfe%>d\'\xdc>5\xaa\xc6=\xf7A\xe9=VY^?\xb8\x84f=\xfa\x95L=\x95\xd7x?\xc0A\x9a>\x9c\xa37?K\x8c]?B\xdb\xc5>\xc5\x19\xed>\xfa\x1f#?\xa2-\xf1<\xc4\xf4B?\xfdQ}=7\x06k>-\xa8\x88=4\xe3\xc7=\x91j[?\xaa\xe5I=\x8f\xeaf?\x97\x7f\x9d>\xb8\x9c\x03?\xfc(\x1b?\xce\xe7\xd7>\xf2\xc8X>I\xa6}?\x8f\xb4E==\xb7.>\xd8\n\x18?\xb4\xc1C?\x8f\x16q?\x88C]>\x06\x99\x0e?mz\x93>\xd1\xb2\x18?(\xb8r?\xe7\xcb\xab>{\x87F=\x9a?\x1a?\x86\x82$?\xf9\x0b\xe9>\x85\xa05? X5?\xec<K?\x81\x115?\xc4\x0e^?\xc3\x1a\x04=H\x0f\xfa>5&)?x\xf1G?q\xfc\x91>\'\xd7\x1a>s\x14A>\xe3\xb1\xe0>Sk\x0c?\x14\x973?\x15\xc7\xd7>z*4?\x14Hq?\x1f\x83\xe8>\x01\xd5.=\x17\xde\x08?z\x1d`>o\x14/>\xd1\xbcA>8G0>\xf2Hh?\xdc\xdfd=\xe9R"?\xfb\xa7~?\xd2\xae\x06=\xe8y\xd6>\xc0\xb7\x8c=\xbc\xe9\x03?\xae\x10\x0f?3rh?N\xacf?\xb5\xfd\x06=\xc5\xf6r>\x8c\\\xfc>\xa2I\xd7>\xb6T`?Hn0>V#3>\xf7\xc9C=\xdaR\xa4=\xfdPh>\x18\xe4&?k}1>\x0e\xbdB?\xb7r|?\xf7\xb9\x17?K\x10\xd8>\xd8f\xa9>\xf6,D?,\x1a\xab>\xf2*w?\xd6\xa0\x1d>q\xcd\xf5>\x01\xf6j?G\xe1q>\xd3D\xc0>\x9a!\xdb>\x81_\xe6>\xea\xa8\'>f\xa1W>\xcdzI?O|,>\xfa\xc5}>\xbc# ?F\xfd9>K\xd0\xa2>"\x06i?>\x9bm?c\xe2\xd8>\x11\xca\xf1=\x06\x08E?\xf2\x0cQ?+\x8d\xfe>`\xb0\xfc>K_\x18<\x02\x13g?hx\xd0>\x9a\x8b\xf3>d\x99H>\xcd\x9d)>P\xb4\x84>\xea\x16o?\x18\x9fD?\x16\xa2">)\xc4|?\tIr?\xdf\xd9\x9a>!\xebu?p:\x0b?X3\xca>\x84\xa9g>\xef\x9d\x8e>\x1ekt?\xe1\xa5N?]\xbe\x06?h\xc8\x9e>\xb0(\x12?\xe1A\xa4>V\xefY<:\x19\xc5>O\xeb1?\xd0P\x10?\x1feT?U7x?\x96]t?\xbd\x82c?\xe1\x87+?\xbcVi?6\'+?\xc3PL?A\x1aR=\x1a-]?\xd8\xae\x1e?\x12K>?\xfc\x00\xf4>\xc5"\xf3=\x17\xc0\xa4=\xe6G\x1b=\x0f\xdcP?\x1d*\xe4>pw\x97>\xe8v\x13?\xf00\r?\n\xd0J>\x87~\xa6=k/^?\x1f\xe5\xe3:V\xbc??\xb4\x81=>;\xd4,?]F#?0D\x07?\xb8\xe7=>\xba\x0fC?\x0fe\x8d>I\x80(?\xa4\x9e\t?\x12\xaaJ?\xdca6>!Uc>}\x0c<?\xcf\x11|?\x08\x1f%?\x00\xbf\xed>\xc3\xcd\x8b<\x02\nG?\x0eFY?\x03\xc4\\?\xce\x96\x95>\xb9\xa95?\xc4)\xb0<z\xfbR?\x9cQ\'?\xa8\x12??\xee\xa8\x17?8\x02\xcf>\xdf[R>\x87\xd24?\x1fSk?\x03\xbdG=\x18o6?x\xdf\x1c>\x10Sc?=\x06\x82>j\xee^?\x96\xc8\x8c>L\xf7"?;\xb4e?H\xfbY>\xa6\x14\xfc;\x9d0\x12?R\xab\xd9>\x06\x8d\'?\x7f%\xc6>\xc4;Z>\xeb\xaba?}\x92\x12>P\xdcq>\x93\xa4\x14?7\x8b\xb0>\xf2um=\xc9Q\xe8=\x08\xdag?e\x13j?j\xefL?\x1eeN?s;\xff>\xc5r\x02?\x86@w?\xb8\x00r>#-b?\x87\xc36>%\x93f?\x88\xd8 ?d\xa3d?\xb0\xe2z?b\xb3\xb7>\xban\xaf=\xcf\xaaE>_J\xde>\x80\xa6\x1b?\xd1@\xd8>670>\x11k\xc5>\xfb\x05\xd4>\xb0\x98N?\xcem\x9f=\xbd\xc8r?+\xcd\xc4<"\xebN>J\x0f\xb2>\xec\xb4E?\x807\xef>\xbc\xa2>?;\\\x12?fM\t?\x04}\x19?:\xff\xa6>\xd5\xe3\x96>\x1cX\xcf>\x89\x19\xe8=\xedc??\x00\x18^?\xe7\x0e\xd9>L\x00i?g\x1a(?1P\x12?\xb8\x16L?E\x97N>\xa4\xe6\xbc>\x18\x02\xa8>\xbc\x12f?r[\xd5>5Ii>\xc2\x1b\xe3>\x14\xc6\x13?\xc3{L?\x7fY\xbb>\xbcq\xc3=XR\xfd>A\xcf<?\x1f\xd3@?\x94\xcaq>@@\x88>\xbf\xe0\xd4>\xa2\xb1??wP\xc1=\xd8\xdc\x17?\xe7\xcc??]\xc6 ?%\xd5\x1d?\x9f\x94a?\x1b\xcf1>R\xcf">l\xa7{>\xe8Df<\xc5\x02L?\xa8\xc9"?\x12\x17\x0f?\xd3\x17\x06?2AE?\x1a\xd9\xc0=\xac\x06h>\\\'\x10?H\xb2\x1e>\xe3=S?E\xee"?J\xa2\x02=,l>?\xa1\x97\x83=s\xf3-?/\x04~?\xa2\xac\x9b>k\xaa\x1a<\xe0\x1c\x06?\x00\xa1s?>\x8f\xe1=\n\x9f\xd7=\xd0\xc1\xc1=\xf0\xf1R?\x99$q>l#b?\x9b\xe6\xd8>\xfe\xa2\x1e?\xd8\xdb\x9b>R\x86L?\x95m\xff=\xd8#\x0c?\xd77\xd7>\x83_\xbf>\xece9>\xbc\xe8\xac<q\x00~>E\x0ei?\x01Kg?m\xa1/?\xe8n\x8f>\xc9@\xb1>\t\xdb&>\x84\r\t?\x9a\xa4=?\xce \x10?\x91\xae\xcf>Db\xce>vB\xc8>\xd9\xffs?X\x83\xec=\xbf)\x18?;\xde\xa0>\x19\xac\x14?\x99\xe6\xed>t\x17r>!g\x03?BD\x86>\xe7\xcbk?\xd8\xa2B?\xcd\xc7\x01>m\xc4s?\xf0)\xdb>xuG?\x10\xd8\x10?;\x04+>-`e?\xc4\xf7\xa8>\xf9\x86\x80=\x04\x11M?\x9e\xe9\x16?:\xe2U?W$\x93>\xf7\xbc{?\xa7\x02E?\x95\xf3\'>\xcd\xb0\x0b>\xe2\x0b\xa3>\xbe4V>\x1fJ.?\xbayg?\x0c\x15\x1d>\xfcQn>\x13\xb6\x91>\xad\x01]?\xbcMb?Yw:?,\xed\x81>\xaf\x87\xeb=\xed?\xd6>\x8cQP?a\x89C?\xb9S*?\xf5\xcb&?1\xc4\xcc>%J\x80>Du\x16=\x05\xd6$>u\x8e\xe0>\xd6\x81L?\xa6\xac\x10?\r\x11i?\xb2~2?\xa5\xca]?\xfa}\xc4>\xc5m5?3R3?\xdb\x13\xdb=\xb3\xa0[?\xf0\xc4V?\xe3\x97\'>\xa0\xf1\x16?=W\xf5=\x17O\xfc>\xf1I\xcd>H\x05r=(kg>EE5>)f3?U\xae\xed>\xdd\xe0\x9e>\x9b4#?`E(?-\xcdA?\xba\x81D>\x87bk?Kr\xf2>\x88\x15+=\xc16\xe6>\x93\x05\xa1>\xbf\x7f}>\xb72*?\x0f\xb4;?8\xc3f>{\xff\x00?A&\xfd>+g\xdf>\xc0\xbf7?\x86\xd9F?~dk?\xc7\\e>\xff\x99\xf4>\xfc\x11\x8b=\xfdda?w\xa7\xae=w\xa8\xfc=\xe7\x10\x02?\xfa*E?\x93L\x1f?>\x8dD?\xdd\xed\x9d>\xb1\x8bQ?\x0eV\x99=F\x7f|?m\x10\xd8>V\xe0\x17>\x9b\xca#?h\x83\xd7>\xa4vX>\xec\xce7?\xa5\xf6\x15?\xe5\x9e\xbf>|\x85\xfb>)7\xf4>\xc5\r\x1e?\x89\xde5=\x9f\xc66?\\\x8e\r?\xde\xb58>JXe?\xcd\xe1\xc3>\x9f.p>\nCw?\xd4\x01p>\x81\\\'?\xa4\x8f\\>\x89\xf1\x84;\xf5\xdfu?\xed\x19\xd9>\x03~\xf9>\x8b\xfb\xca=$\xe4\xb2>\xdb\x92\x01>\xd0\x90:?Le\xff:\x84\'\xef=0QM?\xaf\x01x?\xb7C\n?\xc8\xb9(?qea?\x1f\xbe\x17?\x86\x0b\xdb>\x9f&\x08>A\xeb\xc8=~\xc9\xa8>\xd08\x88>\x87\x88O?j\x96>?x5l>\xdf\x8f(?\xd4[a?}T\x07?\xb8\x0c1?V\x8fl>>,F?8\x8a$?\x01\xf6+?9\xfd\xeb>\r\xf0:>\x13\xd8~=u\xb0{>;\xcc\x11?\x94I\xb3>\xcf\x87\xcb<\x82\xdc\xa6>\xb3\xda\x03?G\x92,?\xc4\xcaG?@\xabV?\x86\xb1\xff>G\x82%?\x93m\xe7>\xb6\xb4\xd0<\xc1^Z?M\x06g>\xf7]G>\x92/\x87>\x03\xe4e?1\xb4\xe9>\x12%\r?\xa7)\x89=/\x18O?\xfcW\xf7>\xa1\xdb\x17?\xd7@\x11?\x04\xea\xeb>_\x912?\x0bK\xd8=\xabat?\x89\xc5\xdc>\x93\xc1\xe0<0\x91\x07?\xa2H\xec>\x16E5?"\xfb]?<p\r?y\xa7s?-\x93\x07>iX\xcd>t\x7f\xe8>\xc7\x88\x80>u\xaf\x11?\xb4`\x02=\xf1\xe6\xb8>.\xd7;?\xeb\xe82>KO\x8d>\xc7\t)?\x86\xd7\xed>z\xf99?\'\xf8b?\xaa\x1bC=\x7f9`?tGi?Kc\xf8>\x97\x96a>\x03\x82\xba>\xfc\r\x85>\xbb\xd3u?j\xb7<?>\xf8\x81>\xd9\x16+?g\xdc\xb7>P\x00q?\x1b\x81+>g\xbea?\xcf\x9b\xe6>O\xab\xbf>S\xe1{?\x18\xec\x85>\x92\xc5>?e\xe8J>\xc7\xf2\xbf>\xbc\xf7\x06?\xc0\x91?>$\x18>?\xdc\x8d">]\x1c\xa5>\xb7!l?\x94\xf4\xb2=8\x05b?\xf9j\x02?1\x1b\x9a>\x01O\x05?\xef\xcb.?\xb7\xe0\xeb>\x872H?\x7f\x1a\xb6>Q\xc4P?F+3?X\xab2?^E+?\xaaK\xaa>\xa5\xbf\xbe=\xc3F\'?\xcc\xb2M>q\xd4.?s\xf9K?e\x0es>\xa2]\x1c?~h\xa5=\x8d\x81;?\x95\xd7\x19?\x9f\xbd\x7f?:\x00f?\x1c\x19\x12>1\xd2\x80=\x81\xb1\x06?\x83\x9bb>5\x8f\xae>-\x9d\x1d>\xf4\x89b?z\xfdT>\xf0n`?,\xba2?\xbe\'\x1d?\xc6\n\xb1>J\xd0k?\xa4\xfcq>\xd4\x02\'??@\xaa>\xc5\xfc\x93>\x8f\x12y>s\xa1\xc7>\xfa\x15J>\x13\x90X>\x9c\x0cp>\xe5\xd0\xf9>p\xb0\xad>Ef\xb3>4\xb1L?^\xa3\x87>_\x8c\x05?:lE<\xfc\xf8w?u\x12\x8a>W5\xf7>\xcb\xb8{=s\xa7\xc9>K\x88P?\x93\\\x93>\xb0\xed\x03?\xdb|-?\xb8U\x1c?\xe1!<? \xc6\x94>n\xcec>m\xa6K>.\xd3Y?\xeeN\x12>\x89\xa8@?\x80\xeaO?*l\x7f?\xa9\xe6\xc0>$F\xcc>\xf3\x8e\xd1>9\x98\xcd=6n\x01?\xd8\x1et?+\xb3I?\x9d\xdc\x11?\xc5v\x10?%\xda:>\xbfC\x17>\xda\x85\xb8=*\xceO?3eS>\xff\x1c1?fs\x1e<\xa12\xce>\xecB\xbf>\xb9$,?\xfa\xe6N>\xdc\xb1H?\xf2\x07\\>\xc6\x9e\xf0>\xce\x18L?K\xc1\x13>x\xd5)?F{q?\xe7f.?S\x02!>39.?\x19c\xaa>}\x9bs>\xcf\x1fx?D\xf3\xd8>!!H?\xa7uD?\x8c\x9e\\?\xb5\x1dY?f\xb0\x04=\x90\xda\xd1>\xd2\x13\r?\x92{\xcb<\xa1\xf4L?\xedh^>\xe6\xe5o?\x86\xe49?oS\x1d=sWs>\xb0c\xad>\x94\x1e\xd5=)\xdf\x12?\xb5A\x1c>\x11\xda{?\xd5+\n?\xd1G\xe4>\xdf^7>\x9e-\xc7=]\xbbp?\x88\x97\xaa=\xfc\xb3y?J\x0c\x0e>\x83\xa0\x89>\xfeEQ?\x93H\xd9>\rZ\x19?\xfc\xe2\xf5=\x93d\x0e?!\xb1\t?\xaat\x19?\xce\xc2\xdf<C\x1c\x9d>s\x8fd?\x17\xd53>\x01\xcd\xd0>\x86\xbfD?\xdbD\x1a?\x17\x81\xac>\xfb.#>\xfe\xfd\x15?\xb8\xa0\x00?TnZ>Q\xd0\x15?\'y\x13?\x04\xca\xe4>^\xc4\xb6=\xa9$]?7\xc1\x9f>S\xbf\xc8>\xa7=k?2\xf7D?%\x03c?O\x99l?\xd4]\xa0=K(\xda>\xa6\x90]?2<\x13?\xb4\x16a?y\x80h?k\xed\xd8>D\xa1\xa7>\xae\xc4\x1f?\xe5|\x05?\xc9g\xe6>\xfc4\n?\xd9\xaf\xf9>\x10@\xf1=% \xe2=\xb5\xae\x1a?\xedv\x8b<\x98\x01~>\x81\xb4\x13?\xa4N\xe6=\xb69-?za\r?\xc6\x00A?\x97\xf2k?\xa7\x06U?\x91\xbfs?\xfd\xa6\xf6=K\xf8=?|\xea\xd3>\xa7\xaa.>\x12\x08F=\xa2\xcd\xf4=\x8doh?\xb8\xe7q?gt7>\x03\x91C?ML\x03?\xe7m/?=B\x06?\xe3\xd2E>P\x1c\x10>uH\\?|\xafH?\xa2\x82|?\xad\x99\x14?6\xb2V>\xe9)\xa8<\x04\xf3\x04?B\xa1$?ne\xc5>\x96\xb2/?\xb0&\xa9=\x8f`\xaa=\xce-\x03=\xbc\x10\xdd>!\x16g>[R\x04?"\xa3F?\x83\xd6B?Z\xefC?\x85yX?%o\xa4>z\x19}?\xf7\xcf\x92=\xf7b\x9b>\x8cG\xcc>\xfeY8?\xd8\x86\xac>\xb3al?\x00\xf5\n?t\xfcx?B\xe7\xe7>W\xb8\xb5=K\xedv?(:I?\x82\x9a\'?\xe3\xef$>fW\xdd>\xf9\x81Q;P\x9a\'?\xfak-?\x1b=+?P\x11E?\xcbG\x07?\x90\xcc\x9f>4W\xfc>E#\xa5>\x08\xf1V?-o\xf7>%W#?\xfd\xda\xa9=*\xab\r>\xb5\x1a\xd1:\xbb\x89Z?1\xa4Q?*\xc7\x05?\xe0u.=S\xbe\x08?\x1c\xe9\xc7> \x95\x9d>\x84\x03+?\x1a9A?\xcb\xb8\xa1>\xfb\xa1\x84=\xac\xadc?\xe5\xca\x81>\xec\x07/?\xc9\xe0p?(TU?\xef\xefP?\xec\xce|>:\xc5\x17?\x1a\x89\x9c>\xab\'F?,\x9eR?\x8d;\xb3>Z {?\xa8\xee\xbb>|\x81m?=\xf4`>\x01\xea\x9e>q68?Xcj?T\x04\x1e?\xb1\x13$?\x88\xea\x9b>\xa8\x83\x08?h\xffd?Vw\n?\x07\x93h?424?_\x1b\xf9>r\xcf]?L\t\xdc>i\xc9q?$B\xce>\xb8\xc6\xb1>\x01\xe5\xa3<\xd6z\x9b>\x15\xecn?\x96\x0c<>7\xa2\x96>\xe1:=?2\x03\xe9>oPr?\x85\x9b\xac>r7\xf3=\xe0^\x0c>\xefk\r>f\xac8?\xbc\xe5\x11?1kS?\xd9\xd3\x1a>M\xfe\\?\xb3J\x14=\x90\xba@?\x98\xfc\x8b>\x01\x8d,?>\x13{?\x0bb4?\x9b\xc7\xd4>b\x16\x99>^9;?T\xec\xd3:^*K?\x1b.\x05?\xa3\xb1\x88>-\xb2\\?\xa9\xd3\xba>y\xda\xb8=\xc2{\'?\x95A0?j\x80S?yB\xe1>:\xa4T=Q\x01y>\xa3-l>-\x08\x19?\xe5\xe6\x08>q\x0e1?\xe7wG?\xcbs$?pH)?\x9b\xb8\xe6:\xad\xc8I>\x8a\x9ad?\xff\xcet?\xaa\x1f\xce>\x92U\xfc>\xe1\xb4V>,T8?\xbbR+>\xf0\xc7a>\xd8\xa1\x90>\x14\xc7b?RFP?6Ps?\xd1G8>\xbcQA>4\x99\xbb>0\xfd\xda=\x89\xdc~?l%R?\xb8\x05\x1e?\x0cS3>\x1c\x8aU?y\xb2P?\x15\x97\xe7>5\x91G?8C\xa5>c\x8e\x0e?\\UP?;4m>6\x024?\x11\xed\x87>}H7?f\x8e&?+\xe4\xc0>\x11\xfdL?\x94\xf1\xef>\xea\xa3\x08?1h\xfa>\xed\xfdJ?*\x13:?\x16:\xe0>\x0c\xd8\x14?\xb9\x1ej?(\x8c\x94=\xce\xe6\xa3>F\x14\x99>r\xf8T?\xa5~\xca=t\xe7e?\xfc\xbd\xc6>+\x8c\x08?\x88\x99b?\xb7\x02|?B\xa8\x87<*\x0f\xea>\xf6\xc8~>\x9b\x92[?\xdcO\xa2<\xa6=Q>\x9a\xfbl?\xa5\x89\xb0>\xf0f\xd5>v1/?S\xbd3?\xb9\xc5D?\xc5\x0f\xff>\x07\x043?\x08\x05\x12?&\xc3G?#\xcb\xb6>$\xf3h>\xf6\xd1\\?z\x85\x03?I-\x1b?I\xf8\xb1>\n*\xb9>\x82\xcd\x1b>\x11A\xd9>VE(?v\xd2\xa4>\xf0\x8f\xc3=a\x89\x7f>\xbcF\x9f>\xe5\x97\x81>&\x1eI?\x1f[\xab=r\xac\x1a;\xd6\x16\x1a?\x06\xfa\'?[\xc1\x13>\x1el(?\x971\xd5>)\xbc\x85>|\xe3;?@KB?\x99\x17\x13=\x1a\x9dP?\x92\nR>c\r}?1+\xfd>\xb61&?\xd7o@?\x0cP5?\xcf\r\x08>\x06Qo?\xa2\xe2Z?\xa5\xccY>X\xda\xdb>]\x8a9?\xbc>u?\xfc\xcc->!\xe27?\xec\xd4Y?\xabj^>v\xa7W?\xeb\xa52?\xbb\x10$?\xa3\xf3;?BOw?\xc6=p=\xadU}?\x14\x9a\x03?\xc8)\x01?\xa7\r\xa1>\xfdKX?\xcf\xab\xcd>\x0ecE>\x88Ox?bx%?\xe8sg?\xa1\xb2d?\xed|\x98>/p\xa1>\x90b\x0c>Rd#?\xde\xda_?\x1a\'\xf7>y\xaf:?%`\xe7>\x99_+?6\x8a\x08?\x19YJ?\xc1\xb1\xd9>PF\xe2=\xd4\x8a\x1b?\x1f\x18\xa5>.\x94<?\xc3T\x1b?VVu>\xd5\xe0\xfd>VC\x17?BE\x0b=\x9a\xf7\xe1>CTK>\x97\x92d?\xec\x1f\x1b?\xe0\xc7J?\x9b\xef\x13?\xdd\x8e\x0b?q\xb1a?\x07Tt?\x91\xa7\xe9=(\xe3\xaa>\x04\x8e[>?\x19\xc8>(\x10\x9f=d[}?\xf2\xba\xa5>N~\xd4;98$?DG\xc8<3\x026??\x99e?'},
 Document {'id': 'doc:b', 'payload': None, 'score': '0.253424823284', 'vector': b'1\x16\xe9>\x9cax?z\xc6c?\x92\xa2%?\xcdk\x9c>\xa3|\x8a>#L\xec>\xc9\xca\xf0;\xce\x1d\x1a?\x12\xe4\xab>h\x88\xe4>\x9a\xb4\xe8>\xb7\x03\xdc=\xf2*l?\xe7\xe1,?(;p?\xceL\x13?\xf5\xfd\xdc=\x19\x92\x84=7\xe1\x7f?\xb7\x898?yR@?\xa4\x1cp?S\xde\xb1>5#\xf4>F4\xc4>\x14R\x18><W\x0b>\xb8n:?/%A?NEU?tu\x0e?\x85\xe8\x88>e\x04\x1b?T\xed4?\x08\xea\x03?\x98\x16p?\x0f\xa4\xfa>$\xb5O>\x9b\xb0~?\x94\xab\xbc>\xa0\xe6G?\x1f\x8bz?s\xca-?\x03\x9e\xb3>\xb4|\xd1=\xf0Z_<\x1a\xe3:?\x06q]>\x02\x0b\x9c>\xdcZ\x1a?L\xb0\xcc=E^\x1a?\x05~\x03?m\xea\x15?\xc4r]?\x0c"\x89>\x9c\xb78?\x87\xf3\x8f>+e\xc0>\x16\xe3@?\xa5\x85M=jq\x12>5.`=T\xac&?\xc7\x91\xb8>\x93\x9cs?\xb1\t\xfa=\xb2\xdfd?#\x8cO?zX&?R*\x05?\x90\x9f\xf7=\x83\x9c\x02=AY\x1d?m$w?\xa6\xc4\x80>\xfd\xceH?\x87\xbaK>\xca\t\xf8<{\x1c\xf5=L\xf9a?TB ?\xae\xcd\xb2=\xd0*\xe9=\x92\x88[?[\x06F?\xb4\xffu?Y{\xbc>\xba\x8bU?z,\r>d\x7fE?\xcd\x85\xb4>m\x91\x9a>z\xa5N?7\xd5\x8a>\x8a\xfbA>n\xa2,>\xf9j\x04?\xe8\x84\\>\xb4A=>\xe8v\xde>\x19\xbaX?\x1d\xd3E?\x90\xcf\x9f=\'\x18w?\xbd:\'?1C\x17?\xac\xaeJ?ae\xef>\xc8_v?\xe8\xfcP?/\x96S?E\x16D?2\xf4~=\xcaV\x1f>\xef\xdb\x1a?\x87)\x11?:6\xfd>uLk?\x9ddT?\x02gc?\xc7A"<\x87\x18v?x\xec8?\x84\xad\xf4=\x0cj\xf6>\x04\xa0\xaf=\xa5\x12\xf0>\xda\x98}?kB\xab>\xd2\t\x9c>\xf0\x90\x8c>\xbe,9?\x1b>S?J\x17[?+\xb2k?\xbdO\xf9=\xb8\xdd\xaa>\xbc\xbc\x1a?\x98\xa3&=\xdbo\x1b?*\x1c\x17?\xacP\n?\x15\x99\xfb=D\xd6s?\x97:~?\x83\x97H:\x814\r?\x1d\xbdt?\x98\t\x0e?\x10\xbd\xf6>\xad)\x80=(\x8b!>Th\x1e?\xfaOX?\xd835?\x00\x8c\x03?9\xf1\xa7=\x80\xbd\x12?*\t\x19?F\xa7\xd2>\x0e\x9c\x1f?\x8d\xed\xf9>\x8bD\xea>\xdb\xe4+?\xb3%\x12?h\xd0F=R\xb5\xc7>\xaf\x99\xe8=\xda\xe4\xe6=J\x073?4;\x1c?|e\xf6=\x99\x8e!?\xdeJ\x9d>5\xa2j>\x06\xdf ?\x99\x85\xfb=A\xcce?z\x19M?\x1f\xccA?\xb3\xea)?Ex\xf7>4\x15%=\xe4\xe1(?C\xe0~?;\x9a\x19?\xe2A.?@\x82\x1a>\xf2\x909?\xcb\x18\xfe>\x87\xff\x11?\xd0-H?h\xd9K?Bps?K\x9b\x0b?|%u?\x1b\xcd\n?\xbb\xdb\xb9>]\xd0\\?\xbee\xb5>*\x9f\x9b=\x8f\x1b\x7f?O\xf8N>\x91\xf2b=\x9a\xe5\xcc=5\xf3o?\x86\x83\xbc>9\xaeG>#\xd4\xbe=\xa9m\x85=\xc3\xa7\xf3<\xf6\xb3\xed>\x94\xcc\x98>\xb7m\x12?\x19\xbaq?\xae\x96Z?g\xa2\x11?j9\xc2>/\xc2f=&\xcf??\xdc\xado?\x01d\x1f?B\xb8U?t\\b?\xc0W\x9c>r\xeb}?\xef\xc9\xe6=\xaf{#?\x89BW?S\xffO?\x8e\xaa\x03?\xfb\xf1\xb5>0\x89\x81>\x96\xed\r?\x88W\xf6>\xe5ZG>\x122\x14?\xe8\x0e\x91>\x1a\xc2\xf4>\x15"Q?\x8c\x87\xa0>\\d\xa7>p\x94-?\xe2\xe5\x17?\x8f\xe5\xdd=\xb9\x04#>_\x9fU?\xd8\x0cL>2Jn?1\xa7\\>\xebT\xe4>NT\x9c>B6\x0e?_\x0fS=\xb6\xcdR<\x96\xb2\xc9>\xbc\xf6\xe2>^\x8f\xa2<\x95\x93\xee=\xf3\xc0C>\xfdw\xd1>\xbc\xba\xf5>\x8b\x13Q?\xa5_\xaf>\xa9\xb0W?\x1bWd>!\xa8\xf8>\x9d\x87\x17?\x84.\x01?G<\x10?\xf6^\xc9=\x8a\x87g?\xae\xc61?\xcbn]>\xe9\xf9+>\x1b\x01\x99>\xcd\x02\x86>\xeb\xe0y?\t.4>\xa4\xb2\x01?;4]=}"\xde>"\xf5n>{\xe7\r>\xbb\x03G??8\x18>\x96\xd1$?\xed\xa2\xcc=\x8d\xef\xd1>t\xf1\x08?\x82\x9cO>~I\xf2>\x0b\xd6\x1d?\xff-">\xb8(_?W\x94o?\xcd\x08A>\xac7\x87>\x15\xaf&<\xab\xcd\xd2>\xf6\xb9\xae=@M\x86>\xb2\x89^?=\x10j?x"\xb9>\x03\x05H?&L}?\x05\x803>\x97\x18\xe4>\x1c\xb9\xaa>\x07\xb5\x9d<\x05\xb1~=\xa9L\xbc><)[?\xdc\x8eC?\xa3\xcb\xf8<k_>?_\x12e?3\xce5?\xef.V?h\x92\r?U<\xa6>\xe6,\x83>J\xd3\x8a>\xf4\xe6*?\xf1y]?\xea\xda\xea=|\xff\x96>\xe4\x8ed?\xff\x00\x82>\x13\xb6\x1e?\x04{h?\xa9\xf4\x86>\x8d\xed\xf9>]\xf3|<\x8d!\t?mq\x94>M6]?\xa5cP=\tb~>\xcf\xd6\x83=K\xb4Z?\rPt>+\x1bW?\x93>W?\xc7E ?\x81\xcb-?D)i?\x99\x02\xb0>\xa4X\x18>:\xc5\xc8>~\x85\xef>=\x7fy>h\x8ee?\x02\xd7Y?\x1bd\xf2<\x82\xda\x0c>\xb9f,>\xed\xd9:?\x12\xf66>\x90\xeek?:+l?+e\xbe>7\x18=?j\xda~?\xd0A\xb8>\x8f2\x95>E\x92\xc0=f\xb2\xbb>X\x8e\x99>\xfc\xcaa>\xa7j\xde80\xe6\xde>\x8d:l<[%\x0c=\xaaq\x05?\xe8\xf7\x89>\xc4\x9c\\?h\xcfG?\xfa\x03T?v\x03k?\xc7\x90\x0c;Y\x8fL?\x15S"?\xbc\t\xd9>\xc8\xda\xa4>\xcf\x82+?\xe0\x11\x1c?\'\xe2\xc5>a\x031?\xd4\x08G=\x82\xb5\xd5<\x9e\xa7j?b\tx>&I\xc1;\xfa\xc0c?8$\x0c?t\xea??\x1eoT?\x02*l?\xe0\xee\xa0=3\x0f\x84>\x81\xae\xbc=!E\xed>\x0b\xee\x80=|^\xeb>\xb6\x0b@?\x1a\xb5v>\x86\xc5M?\xb3]k?x\x0e\xe1>\xb0d\xcb>\xe5\x7f\xa5><\x89\x10?{\x96\x96>\x9bqf?\xf6\x9cd>b\xee\xbf>\x8dP\x00?\xbe\xa8;>a\xf0\xd4>?\x89T?\xbf\xff\xb8=\xe5\ry?\x1b\xcb\x02?\xb7S\x19>\x0f\x96&?\xa1\xca\x18?[A)?y\x8cX?\xf5O#>\x85\x8f\x11>}\x14\x81=UN\xb6>\x8fi\x92>\x9d\x84A> \xd5\xad>\xff2\xa2>yG\x18<\xb5m/?cW.>#\xa1e?\xa0\xfa\x1d?\xcfd\x16?E\xaal?M\x87x?\x8b0\xe6>\x10MW?\x01<\xd1>\t\x990>\xa32\t?\xfd\xe3/?\xa9\xe5=>\x7f\xdd:>a,\'>Eo\x06?\xe9\xabe?\xc5\x879?\n\xe5h=\xd4\x0b^?y\xa7G<\x02A\xf5=\xf7Hy?\xe3\x9e ?\x82\xb6>?~\xf8\xf4>\x90\xd8\xaf=\xfcpX?\x1d\xa5\x1e?2\xc11?\xadf\xe1>\xcf\x1c\n?x\x0f\xd8>\x86\x02\xa9=\xb8\xb3\xcf=\x11\x91:?\x92\xf4\x0e?\xbf\x14\x9b>\x93G\x7f>\xaa-\xea>\xf1\x95\xbb>\xa0*\xde>R9\x7f?\x95\xe2N>B\x84\x12?2\xa0u?\xadbD?\xbb\xefO?i]\xf8=b\x05\t?g\xd6\x80>F\xf6[?n\xde\xb0=\xa2\xbdj?I^\xfd>\xb7k\x07>\x1bE\xf8>vB\xb7>O%=?T\xebF?\x90\x87m?Q+\x16?YCc?\xba\x08\xb4>\x0fNT>xe\x0e?\x974P?\xc4\xbdi>\x8bu\x81>U;\x1a?|\xae8?\x1f\xef\x01>4M\xaa>\x7fgr?\xf8\xd6\xba>z\xa0\xbc>}\xde/>\x90\xbeI?\xa5\xc2e?\x9e\x0cf?\x95:J? \xb2\xf3>\x00\xf6p?\xdaZE?\xce\x18\x1d>\xe8\xdc`>\x9f\x03\xa0>\xe1\xf9\x1d?E_\xcd=\xdc\x1e9?\xb3?a?\xcfnf?\xc1$\x01>5S\x11?f\xf38?0z;?\xfd\x8cb?C\xe1\xe6>\\\xd3S?l_\xa5>k\xe8\x1f?\xa7\xe3\xea>\xb5$p>\xa9\x90\x05?z\xf4P>&\xb0\x0b?M\x8b\x08?\xdd\x94\xcf>MA\x0b?\xea\x12\x19>l\xf2\x1a>\x9e\xecs?\x1a=\x83>\xd9\xc5\t?n.2>\t\xb73?\xbb\x9f??\x15=a?s\xd5N?\xb7\xc9b>`\x1dP?\xa2\xd0\x80>\x04\xf4\xd0>\xf6,K?~\xb2z>\xcc\xa5s?$\xd0f=\x1f\x86\x1d?\x17\xc8v>\x11\xd8@?,@0?\xc7\xa9\'>\xc0/\x1b?!\xbb\x85>I\x9a\xb5=7\x8dx?z\xa7w?w\xb4\x1e>6\xb8\x7f>\x8a\x86\xca>K|`?\xd5\xc7\x19?\x99E ?0@%?\xf3\x0f\x10?\x9a\x01\xa2>\xc5\xbe]?\x13LR?V\x0eH?\x7f9\x13>\x10\x10\xce>\xba\xd6\x00><\x03\x87>\x1d/\xaf=Q\x06x?6y\x03<\x9c\xa88?\x06\\\xa0>\xf24\xe8>\xe57V>\xe4\x803?\x0fu5?\xb8\x02\xd2>:P!=\x08\x98\x88>&\x1dW?\xf9f\xcc=BU&=;\xb5\xd6>\xa1\xa5\xb3>wj`?\xf9 g?\x02A+?\x12\xe4H?\x99\xb4\xf6=\x15\x02\xed>\x9eKZ>\x14vX>\xc7\xe2\'?_\xd16?e\x166?y\xc2R>\xc3\x93n>\xc8\x98\xc9<\x9d*\x01?\xf1*\x8d<\x9e\xe2\t?\xbb\xcdS?C\xdc\x0c?\\\xa6h?\x9a\x13\x8d>5\x023?$+\xcf=\xd5H\x03=w\xba\xba>\x1f\x86P>0\x06\x0c?*\xac\x03?\x8e\xeb_?\x14~\x14?\xa1h=?*<\x94>\xe3\'\xa5>&\xfb2>\xf7\xbc\x9a>2\xc2\xf6=a7\xad=<3\x03?\x89\x16u?f\xa2v?\xfc{\x05?\xe9\xbf\x95>\xc8\xc9\x0e?\x81\xf9D?\xbd\xc8\x18?\xe7Y\xb9=\xa8\xac\xa8>\x109c>\xd4\x04\x18?7\x859?\xa2e\x92>\xcf\x9d\x11>\x95\xe6\x94>\x17\x02\xf1>\x85\xd3Y?\xa0E\xc6>\x80n\xe2>/\x03\x10?\x16-\x8b>\x95h,?r\x1a\x11>2L\xe3=\xa0\xf8E>\x8b\xc3\xfd>\xebN\xc2>\'=\xd2>\xc6\xadM?\x04\xe8\xf6>\xf2\x89\xc5>*JG?\xdb\x1db?o\x9bg?"\xf7o=ly&?2\xf6f?2%\xd8>\xaf70?\xfdV\x82>\x1a\x10v?\xa4\xe9\xd4=e\x8cK?\xf2=\xe5=\x8d\xa9u?C\x1c\xff>Maq?I\x97\x10?t\xbf\x04?\xe3Z\x00?\xa5\xec\xf7=\x0ew\xbb>3jP?\x1eS\xec>\xdb\xe1??\xde\xb5\x15?\xb1\xc0H>\x0f\xf7,?F\x83\x8e=\xd5\x08_?\x1a\x0fo?i\xe3p?\xe0\x1a\x11?_\x0cI?rF"?P\x82&?\x94\x8fY?\x0f\xb5c?\xc5$\xa4>3-}>\x05\xdcV>\xeb.\xe1>\xa5\xf8\'?\xbd\xaaN>\x1b\xc3\xce=\xad\xc2\x0f?R\x80k?\xb0\x95\xf2>\xa8\xe7\xb8=,3\xb0>\xc0i4>9\xd1\x1d?\xc5\x8d\x11?\x17\xeb\x13?\xed\xecE>\x88\xb6Q?Ou\xea>\x84<\xed><\xcf\x02>\xec\n\x90>\xb1\xe4\x15>9\xf8U?\x90\x91\xb8>\x94N\xd6>\xbc\xf2\x0f>\xaa\xae\xb8>\x83 \xe3>fH\r?\x8a\x19\xae>c\xe3\x8c>x#w?\x07*\x14?\xba$\x89=\x0c\xe7T?\xbb\n\x14?*\xa5\xd5>@\x15\xd4=\x1d}1?\xaf\xbb\x1a>\x83\x18\xa8>0\r\xeb>\xabt\xf3>\x1b\x9f\x03?}\xd7k?2+c<\x04\xf2\xe9=~B=?\xc4an?`\xd9\xb3>\x82\x92\x7f?\xba}\xa9>\xe75j=\xe8\x9f/?\xd4Z\x19>\t\xaa}?>\x97\xa6=o\x1b+>\\\xca\xf9>\xe3Xl?C\xa3T??*\xf2>\xe1\xd7d?\x90M\xb2>2{U?\xba\xd0y?\xe47M?M\xca7>3\x84\x1e?\xb0D\xfb>\x1d \xc9>~I\x16?\\O\xf3=:\xbf#?DT\xdb>\xa9\x901>e\xd9\x16>\xae\x13\xa3<\\\xc5\xfc>\xde\xabk?\xd7\xcc\xdb<\xdf\xb6;?\x99\x13)>\xc7q`<,\xa5\xe3>\xb6\xfd\x02?\x15\x11\x06?ia/?8\xf1D>U\xddf?\n\x9f(?O\xf0d?\xa114?\x85\xca[>P\x89\\?\x7f\x1df?r\xdd|?\xb8\xcfV?\x96AS>gs\x0b>}\x89U?\x89\x18+?\xa0\xf4\xb1>\xf0\xf3n?\x8aQ\x11?p\xbdI>\xed\x10%?\xdc/\x08?j@\xcb>C\x04\x8b>\x8b9\x11<\x8a\xc2 ?\xb8,7>\xd7$\xeb>\x8f\xc0w?\xfc\x0fb>cJi?\x00\x14\x0f?\xeb\xb9:?\x18!`?.\x18\'?\\\x98Y?\xc1\xe0\xa9>~\xae2?\x8a\xe0\xa0<\xec\xf0&?\xf71J?\x92u\xef>S\xfem?\xd6\xea}=\xfa@\x99>8\xffo>\x83\xddq?\xf3m\\>%\xfe\xbf>\xac\xdc\x1c?\xba\x80Y?\x01\x08W?`\xf5i?\xb0\xda\xdf>\x08@>?\xc8\xb6\x8a>\x98_\x0e=\x88r\x9e=\x94h]>\xa5\xba*?\x0c\x10!?.\xbe\x9a>\x87R*>-2\x8b>\x89\x08I?*\xf5&?\n40?\xe1\xa6o?\xafW\xf1=i\xb6\x83>\x10\xe0\x18?\xb48B?\t\xaf/?\xdf3o?)jY>i\xce\x97>X f?x\x84\xbc>d\x7f\x19>\x00(\xe4>\xc7p[?J\xce$>\xe9\xbeq?M$O?\xdd\x0b5=v\xfaS>d\xa5t>bj\xec>\xab\xees?v)7?\x9d\x03\xd7>\xbc\xa9\x98=\xc7x\';\xa4\xb2\xdf>\xfe:\x06?\xde\'\xeb>\xf5-\xa7<\x9c\xc9f?`\xf9@>\x1e\xffh?\xe1\xd7\xbb>\x84D\xbd>\xf4(\x7f>D\x15U?T\x9e\x80=>\xbbO?\xa8R\xfc=)#n?\x91\xd8\t?k9Q>$\x9a\xad>$\xd3b?\xee\xb6.=\xc0\xf8\r>\x87\x8f\xa1=\x95Y]?P\x0f\x1a?\x14\t\xf0>n\xa1\x16>@\xff\xbb>\xa44\x03?<\x87\x8d=e4\xd1>\xbb\x1fD?\x84-\xb9>\x11\xc6\xab>\xce\x99|?\x82\xde9?C!\xb1=nXh?|\\\x12=\x8a\xea8?Q\x80i?\xf6\xf3k?\x8c#n?\x07\xb6"?b\xe5.?\xc8\xa0y?&{i=\x1c\xeb\xa6>\x14\xc3\xb6=6rW?\xb3\xd2\xbc>t\'k>F\xca\xa7>e\xce\x05?JL\xa2>\x13\x02\t?\xbcF\xc6>\xaf=u?\r\x16p?\x0e\x002=\x9b\x89\xfa=\xcdY\xb0>+\xf4c>\xe2Wl?\x90m\xa8>\x14)\x18?m\xff\xc7>\x8f\xda\x1d?\x19\xa0\x1d?Q\xfbv?\xcb[\xae>\x80\xc3\x9c>\x1eP\x17?G.\x9c>d\xcdD?7\x1eC?\xb9hK?E\xdf\'>\xccPQ?\x8b\x1a\xcb>\x81^T>\xe7\x9b\x97>:\xa2\xbe>\x84e3?\x00>\xe1=\xc0u\xd0=\xc3\xb6\xca=y\xbaL?\x1eU\xb7>\x1f`\xcc>\x16\xf1K?\xb4\xed*?\xa5\x83\x16>_\xdd\xfe=\x0c\xa3\x01?1y\xdd>\x7f\xaa<>\x97[\x14?*\x7f[?n\xf3:?3g\xf6>\x96\xa1x>%n\x96=\xfa?\x15?\x08\xf3\xac>\xe8\xefh?B5\x7f>\xfd\x9cu?L\x0ew>.\x1f\x8c>\x11\xae\xf0>\xe1\x0e\x01?\xca\xac\x17?8\xb4b?\xd3\xa9\xbf=\x81\x17i?\x18\xd4\xd3>X\x99\r>\x1af\x1e?\xc4\xaaa>K\xd8\xb9>B\xb3\x0c?\x9d\xbdB?\xb0PN?\xad\x1ah>\xb9\xfaL?\xf1@*?\x9d+V?1\xf9\xe4>\x17\xb1\xc2>\x9e\xa3\x85;\xae4\xdc>\xdfw\x1a?\xee\xabQ?\x0f\x1ab?\x05\x1f??^\xedz?n\xff\xde>\x18W\xbd=ZT\x92>\xe1\xba7?\x86\xd5\xf6>g\xee\xa0>\xa6R\xbd=\x1e\x04\x84>\x07\x9e\xe6=\xc3\x03"?\xe2y\x94>\xf0u??~\xafA>\xfax\x19?\xc2=\x01?/\x812?\xad\xd2\xd8<\'\x80\xb1>\x9c$\xff<\xe6\x0b\xca>S\xa6\xda>\xe8_u?\xa4O\xd8>7t\x1b=\xcbA\xd3>\xa6\xa9\xee>\xe7\x82\xfb>\xad\x86x?$\xbcc?\x83\x9bI?\xcf\xe48?\xb5\x0fm?\x7f\xf75>$\xa3G?\'\xee\x0b>\x17\xc5\x12>\xbb\x83Y?\xfc\x01 ?-\x9en?U\xe5$>\x10\t\r?v\x05Q?/*\x1c>\x06\xa5t>KNR?\x06\xb8\x16:`"D?\x9c\x94\x04?\x1e\xa2#?\xfc\x8b\xe3>\x91\x1fN?\x1c\xd0\x17?\xd3{\xe8>\xe6,4?\xe9\x8fP?\xf1r\x83>\x80\x85\x80>\xa7u<?\xac$\xe1>\xb2y\x94>\x88F\x1f?)H\xc7>\x89]\xf9>\xf5\x03\x82>R\x8c\xd0>3\xaf>?\xc4&b?\xab\xfbW?\xf8VL=J\x81V?.\xe1x>\x7f\x1ei?\xb1\x16k?\xe5\xe24> 5z=\xfd\xed\x0f>\nN\xc9>\xb4\x84\xfc>@\x13k?\xea\x0b[=\xf1.l?\xdc\xf9"?\nr/?\xc1)=?B\x14,?YD6?WK\x0c?\x05F\xfa<c\xe2\xb2=\x8f\x0e\x12>\x9cW\t?\x8a\x0c\x1f?i=\x15?nq\x02;\x9d\xefj?^eA>0\xc2=?O\xca\xf2=\'\xb9\xf1=\x96Y\x1f>W\x838?x\x1a\xe5>\x02r\x1f?\xca\x14\x1a?\x0e\rU>\nG\xb1>\xcdKP<\x18\x83\x93=\xdf\x84\x88>p\x02\xa6>\xad\xc3\xe9<\xe8\x07_?\x92U\t?\x1bs\x00?\xc0\xb1\xc6>\xef\xfc\xca=k"8>\xb2,\x00>\xa6\x1d7>\x17\xc1\x05>l.N?\xd3i\xb3>\xdd\xc0\x0b?\xfdmn=H\xf0\xd3;ZN/?H\x15\xb4>L*n?Nq(?E+]?$\x92\x14?x\x9b\x1b?^`\xbb=\x0e\xc8r?\xb47<>\xcdv\x1d?\xc3\xda\xe0>6P\xd2>A\x99\xc4>0\x85X?\x86\xe8%?t*\xb1>\xbf\xb0\xaa>N\xb9\xfd>\x10d\x92>\xf7X\x0e?\x04\x9c\xb1>HM\x16?\xf8\x1c\x82>\x01\xb2\xab=\xa2\xce\x15>\x9e\xcdl?bb1?wz\xf6<Y\xd5d?x@\x1d=\xf9\xed\x10?\xe2\xbf\xd6>\xcc\xfa\xa4>]\x86B?\xb8\x9aV>\xe7\xe86?\x10\x9f\xea==P,?\xc2T\xc0>0p\x1d>?}\xd6>\xd4\x08\xfd=\xe5}\x92>\x98\x95\xd0>\xf1\x8f\x0e>\x07OV?\xd8F\xc9>\xf0\x95\x10?\xdc\xf9i?\x95\xc8\xb6<\xa0%\\>\x15\x99??\x1c\x8a\xfe>*<->\xc0\xf9\xba=\x17\xa1\xd0> O\xff><\xfd^?\x1c\xb9\xbf>\xbed\x8f>\x8c\x14\x7f>\x12j\xbc>30x?\x8b~\x85>\xdez\x17?m\xd1_?\xc0\n\xde>\xecV\x84=\x0fj\x84>\xb8)\xef<=n\xe9>~\x8e\xf0>\xee\xc3z?\x9a\xa5-?\x1d\xea7?\x14\xec\xc3>\x1a|W>\x00h\x97>\xc9\xe0\x89>t\xdeH?\xf4PN?\x94X\x13?\xbd\x10\xa5>\x7f\xab6?\xce\xab\x07?\xceQr?/t\x1d?H\r\xf2=\x0bX\xae<\x11\xb3\x0f?\xff\xe7N?\xf5\xcf%?L\xe8.?\xf7A\x19?\x05\x18%>/#\x91=\xd3A\t?\xbb\xce\x06?\x1bS\r>\x13\xd8.?(+\x15?\xf9\x1e\x01>\xdf\xf1\x96>\xe7\x953?Y\x1d>=\xd9\xf4\x91>\x16wA?\x84V8?O\x8b<=\rd\xbe>\xf1\xc2\xcd>-\x10:?\x02>\x96>VI\xbc>n\x9b\x10?\xbf\x97\x14?A\x85\xce>a\xae\x9e>U5%?d\xda\x01?\xd5N\xa2>\xcd\xe0\xf6>:\x9f\x1d>V"9?\xa9\\\x04?u2t:+$\xfe>\x18\x00??-\t\xcd>\xdd\xe3W>\xe1\x8c*?\xd0\xa2\x11>U\xa0x>\xf6Hk>\xddwP=\x85cg?\x9d\x18u?z\xceb>4\x11\xd6=\n \xe9>W\xff\xcc>\xb8\x0b\x95>\xab\xcd\x0b?\xcc\xf5q?dI=?\xb9\xa5x?\x92\x02\x1c?\xabm\xb4>N\xa7%?A5\xcc>;;u>>~\xed=\x8fp&?\xa3K\x8c=%r\t?\xb6ns?\xa1\x89H?\x01=\xc0>\xce\x1e\xfd=\x08\xfc\x91>\x97D\xa6>\x01\x9ae?w\xe4\x9f>\xd8\x14\xb7<i#q?\xd1\xbd\x05?\x9a\x00\x13>d\xac\t?\xd5i\x8a>\xdf\xb4\n?S\xa0\x1f?Pu1>J\rd?\x02\xc8M>\x97\xb9E?\x0f8c?\xcc\x14&?\xd5\xa6\x95=\r\xdd\x80>I\x81G?\x8eC~?h\x07L?A?J?\x15j\x0f?\xcat\xf1>\x8a.\xcb>\xee\xacy?,Q\xdf=\xa4>\xc2>-\n\x11?-z\xf8=oV1>\'\xf9B?\x86W\xa2>\x9f\xd8a<\xfd1\x07?&\xd1\x16?\x0c\x17\xe0>\xbe\tP>T@\xeb=\xfe:\x97>\x05o\x83;\x9d-"?Ks\xef>\xde\x8e\x13?\xc9\xe7\x98>[\xdb=>\xafs!?9\xe7\xae=\\\xce\t?F\xec\x93>\xd4\xe05>\x9f\xa5:>\xefe\xa3>Z\x8e\xfa>\x12\xc7\xda<\x91\xbd\xfb>E\r\xbd>37T?\xf6\xdc%?\xc28\x01=DB\xc7>K\x022?\xb5\xd3\x8a>\xb1\xd3H?\x1f\xe2q?\x1b\x91k?\xa5\xb0$?\xee\xa6\xa4>(\xae\xe6<\']\x18?\xf5\xce\x95>\xdc\x06\x1f?\x06\xa9\xce=\xe0u\xbb>e\xc1j>:\xf4D?\n\xc6\\?\x83\xb7Q?\xebT\x15?%g0>?\xa7s>C(@?\x86GQ<`go?_\x8dp?!B\x8f>\xd1\x16\xea>\x03\xed\xbe>ni\x13>ezA>\xdf<\x02<\xda\xe1x>\x91\xd6\x81>\x1c.k?\xe6\x8b\xa7>\xea<P?v\xec<?\xd8\x12q?\xe9\x00\xda=\x1c\xf8\xce>f\xa7\x1f?}\xf7a>\xff\x96q?\xd2\xf8\xed>f\xd0<?\xcd\x06\xe8>B\xb6\xd9>0W6?\xc2\t\x19?x\x909?\xc7\x06\xd6>Xa\xae>\n\x12\x06?_\xacq?\x9d\x85L<8\x8f\xdf>\x87\xfcE?\x89\xbbT?\x0fb{?<b\x82=}\xe8\x04?\xafA\xab>a\xf6\x86;{\xa6T?\xca\xb2\xeb>\xc8\xa0\xca>\x08\xa5q?\xe4`\x85>\x7f}\xb6=k\xe6W?\xd0\xaf3>,\x1e)=\x02\x0f7?\xb8\xd4r?\xfa\x0bD?\xc5\x8b@?\x1dFQ?\xdc\xdd_?!\xb0\x06<\x04v\xbc>\x12kN?\xa7*\xd7>\x8ab\xa2>q]N?\x8b\']=9\xefF?\xcd\xc6\t?\xf3OO?\xc48e>*vC>\x80\x9a\xc3=\x8d\xa9J?L@j?\x985\xb3>\xa0\xd5\xc9>\x7f\x04\xc0>\x94\xeb\x0f?F\xa9\x91>h\xf3\xed>\x08\xbe\x1d>-\xc79>\x0b[R?\xcc\x17\x06?\xf5@\xe3>5\xc1_?\xceF\xb0>\xf8\x8d\xb9>\x10{3?\xf5\xce\xee>\x89\xceu?:\x14f?\xb7\xc6\xf2=y\xc5\xa1>\x13\xd8t?6d\xbc>X\xd2\xa4>\xdb\x1ez??\x15\\?\x9a2\x1e?\x8b\x9eS>j\x92\xe0>\xf3\xcb\xf3=\x12\xdb\t?\xb8\xd8_>\x8a\x11A?\x93\xc3\xdf=\xb8\x9bq?\xe0\x9a,?\xd3\xe6^>\xb6\xecQ?\xba\xa0\x85>\x95\xcb\x90=\xc6\x8b\xba>\xdd\xafq?vj-?\xdc\xd0\xe7=\xa0\x1f\xca>v\xce\xb9=/\xa9;?Y_\xcc>\x99\x8e0?\xf55.?+9\\>y|\xba=\xa4\xe9\x14?.%\xb3>\xde\xd9\x1e?w,\x88>\xad\x86\x94=\xa0\xd8)?\x9f\x1d\xb2>\xdbx\xa9>U4\x00?#\xbcX?I\xc3\x8e='}]

范围查询(Range Queries)

范围查询提供了一种通过距离过滤结果的方法,该距离是在 Redis 中的向量字段与查询向量之间的预定义阈值(半径)基础上进行的。

[6]:
query = (
    Query("@vector:[VECTOR_RANGE $radius $vec]=>{$YIELD_DISTANCE_AS: score}")
     .sort_by("score")
     .return_fields("id", "score")
     .paging(0, 3)
     .dialect(2)
)

# Find all vectors within 0.8 of the query vector
query_params = {
    "radius": 0.8,
    "vec": np.random.rand(VECTOR_DIMENSIONS).astype(np.float32).tobytes()
}
r.ft(INDEX_NAME).search(query, query_params).docs
[6]:
[Document {'id': 'doc:a', 'payload': None, 'score': '0.243115246296'},
 Document {'id': 'doc:c', 'payload': None, 'score': '0.24981123209'},
 Document {'id': 'doc:b', 'payload': None, 'score': '0.251443207264'}]

请查看 这个 Jupyter 笔记本 中的其他范围查询示例。

混合查询(Hybrid Queries)

混合查询结合了传统过滤器(数值、标签、文本)和向量相似性搜索(VSS),可以在一个 Redis 命令中同时使用。

[7]:
query = (
    Query("(@tag:{ foo })=>[KNN 2 @vector $vec as score]")
     .sort_by("score")
     .return_fields("id", "tag", "score")
     .paging(0, 2)
     .dialect(2)
)

query_params = {
    "vec": np.random.rand(VECTOR_DIMENSIONS).astype(np.float32).tobytes()
}
r.ft(INDEX_NAME).search(query, query_params).docs
[7]:
[Document {'id': 'doc:b', 'payload': None, 'score': '0.24422544241', 'tag': 'foo'},
 Document {'id': 'doc:a', 'payload': None, 'score': '0.259926855564', 'tag': 'foo'}]

请查看 这个 Jupyter 笔记本 中的其他混合查询示例。

向量创建和存储示例(Vector Creation and Storage Examples)

上述示例使用了虚拟数据作为向量。然而,实际上,大多数用例利用生产级的 AI 模型来创建嵌入。接下来,我们将使用一些示例文本数据,分别将其传递给 OpenAI 和 Cohere API,然后将结果写入 Redis。

[8]:
texts = [
    "Today is a really great day!",
    "The dog next door barks really loudly.",
    "My cat escaped and got out before I could close the door.",
    "It's supposed to rain and thunder tomorrow."
]

OpenAI 嵌入

在使用 OpenAI 嵌入之前,我们需要清理现有的搜索索引并创建一个新的索引。

[9]:
# delete index
r.ft(INDEX_NAME).dropindex(delete_documents=True)

# make a new one
create_index(vector_dimensions=VECTOR_DIMENSIONS)
[ ]:
%pip install openai
[10]:
import openai

# set your OpenAI API key - get one at https://platform.openai.com
openai.api_key = "YOUR OPENAI API KEY"
[11]:
# Create Embeddings with OpenAI text-embedding-ada-002
# https://openai.com/blog/new-and-improved-embedding-model
response = openai.Embedding.create(input=texts, engine="text-embedding-ada-002")
embeddings = np.array([r["embedding"] for r in response["data"]], dtype=np.float32)

# Write to Redis
pipe = r.pipeline()
for i, embedding in enumerate(embeddings):
    pipe.hset(f"doc:{i}", mapping = {
        "vector": embedding.tobytes(),
        "content": texts[i],
        "tag": "openai"
    })
res = pipe.execute()
[12]:
embeddings
[12]:
array([[ 0.00509819,  0.0010873 , -0.00228475, ..., -0.00457579,
         0.01329307, -0.03167175],
       [-0.00357223, -0.00550784, -0.01314328, ..., -0.02915693,
         0.01470436, -0.01367203],
       [-0.01284631,  0.0034875 , -0.01719686, ..., -0.01537451,
         0.01953256, -0.05048691],
       [-0.01145045, -0.00785481,  0.00206323, ..., -0.02070181,
        -0.01629098, -0.00300795]], dtype=float32)

使用 OpenAI 嵌入进行搜索

现在我们已经使用 OpenAI 创建了嵌入,我们可以执行搜索,以找到与某些输入文本相关的文档。

[13]:
text = "animals"

# create query embedding
response = openai.Embedding.create(input=[text], engine="text-embedding-ada-002")
query_embedding = np.array([r["embedding"] for r in response["data"]], dtype=np.float32)[0]

query_embedding
[13]:
array([ 0.00062901, -0.0070723 , -0.00148926, ..., -0.01904645,
       -0.00436092, -0.01117944], dtype=float32)
[14]:
# query for similar documents that have the openai tag
query = (
    Query("(@tag:{ openai })=>[KNN 2 @vector $vec as score]")
     .sort_by("score")
     .return_fields("content", "tag", "score")
     .paging(0, 2)
     .dialect(2)
)

query_params = {"vec": query_embedding.tobytes()}
r.ft(INDEX_NAME).search(query, query_params).docs

# the two pieces of content related to animals are returned
[14]:
[Document {'id': 'doc:1', 'payload': None, 'score': '0.214349985123', 'content': 'The dog next door barks really loudly.', 'tag': 'openai'},
 Document {'id': 'doc:2', 'payload': None, 'score': '0.237052619457', 'content': 'My cat escaped and got out before I could close the door.', 'tag': 'openai'}]

Cohere 嵌入

在使用 Cohere 嵌入之前,我们清理现有的搜索索引并创建一个新的索引。

[15]:
# delete index
r.ft(INDEX_NAME).dropindex(delete_documents=True)

# make a new one for cohere embeddings (1024 dimensions)
VECTOR_DIMENSIONS = 1024
create_index(vector_dimensions=VECTOR_DIMENSIONS)
[ ]:
%pip install cohere
[16]:
import cohere

co = cohere.Client("YOUR COHERE API KEY")
[17]:
# Create Embeddings with Cohere
# https://docs.cohere.ai/docs/embeddings
response = co.embed(texts=texts, model="small")
embeddings = np.array(response.embeddings, dtype=np.float32)

# Write to Redis
for i, embedding in enumerate(embeddings):
    r.hset(f"doc:{i}", mapping = {
        "vector": embedding.tobytes(),
        "content": texts[i],
        "tag": "cohere"
    })
[18]:
embeddings
[18]:
array([[-0.3034668 , -0.71533203, -0.2836914 , ...,  0.81152344,
         1.0253906 , -0.8095703 ],
       [-0.02560425, -1.4912109 ,  0.24267578, ..., -0.89746094,
         0.15625   , -3.203125  ],
       [ 0.10125732,  0.7246094 , -0.29516602, ..., -1.9638672 ,
         1.6630859 , -0.23291016],
       [-2.09375   ,  0.8588867 , -0.23352051, ..., -0.01541138,
         0.17053223, -3.4042969 ]], dtype=float32)

使用 Cohere 嵌入进行搜索

现在我们已经创建了 Cohere 嵌入,可以执行搜索以找到与输入文本相关的文档。

[19]:
text = "animals"

# create query embedding
response = co.embed(texts=[text], model="small")
query_embedding = np.array(response.embeddings[0], dtype=np.float32)

query_embedding
[19]:
array([-0.49682617,  1.7070312 ,  0.3466797 , ...,  0.58984375,
        0.1060791 , -2.9023438 ], dtype=float32)
[20]:
# query for similar documents that have the cohere tag
query = (
    Query("(@tag:{ cohere })=>[KNN 2 @vector $vec as score]")
     .sort_by("score")
     .return_fields("content", "tag", "score")
     .paging(0, 2)
     .dialect(2)
)

query_params = {"vec": query_embedding.tobytes()}
r.ft(INDEX_NAME).search(query, query_params).docs

# the two pieces of content related to animals are returned
[20]:
[Document {'id': 'doc:1', 'payload': None, 'score': '0.658673524857', 'content': 'The dog next door barks really loudly.', 'tag': 'cohere'},
 Document {'id': 'doc:2', 'payload': None, 'score': '0.662699103355', 'content': 'My cat escaped and got out before I could close the door.', 'tag': 'cohere'}]

在这个 GitHub 组织 中,可以找到更多使用 Redis 向量相似性搜索的示例应用、教程和项目。