Redis作為一款高性能的內(nèi)存數(shù)據(jù)庫(kù)熊榛,廣泛應(yīng)用于各種場(chǎng)景蹬敲,如緩存识藤、消息隊(duì)列和實(shí)時(shí)計(jì)算挖垛。今天,我們將探討Redisearch模塊刻两,它可以讓我們輕松實(shí)現(xiàn)K近鄰查詢(xún)增蹭。本文旨在幫助Redis初學(xué)者理解K近鄰查詢(xún),并學(xué)會(huì)如何利用Redisearch實(shí)現(xiàn)這一功能磅摹。
什么是K近鄰查詢(xún)滋迈?
K近鄰(K-Nearest Neighbors,簡(jiǎn)稱(chēng)KNN)查詢(xún)是一種機(jī)器學(xué)習(xí)方法户誓,它可以用于分類(lèi)饼灿、回歸和推薦等任務(wù)。在K近鄰查詢(xún)中帝美,我們根據(jù)數(shù)據(jù)點(diǎn)之間的距離(如歐幾里得距離或余弦相似度)來(lái)確定它們之間的相似性碍彭。KNN算法的基本思想是:對(duì)于待分類(lèi)的數(shù)據(jù)點(diǎn),找到距離它最近的K個(gè)訓(xùn)練樣本點(diǎn)悼潭,根據(jù)這K個(gè)鄰居的信息來(lái)預(yù)測(cè)待分類(lèi)點(diǎn)的屬性庇忌。
什么是Redisearch?
Redisearch是Redis的一個(gè)模塊舰褪,它提供了全文搜索皆疹、索引和聚合功能。通過(guò)Redisearch占拍,我們可以輕松地為Redis中的數(shù)據(jù)創(chuàng)建索引略就,執(zhí)行復(fù)雜的搜索查詢(xún),并實(shí)現(xiàn)高級(jí)功能晃酒,如自動(dòng)完成表牢、分面搜索和排序。使用Redisearch贝次,我們可以利用Redis的高性能特點(diǎn)崔兴,實(shí)現(xiàn)高效的搜索和實(shí)時(shí)分析。
如何使用Redisearch實(shí)現(xiàn)K近鄰查詢(xún)?
為了實(shí)現(xiàn)K近鄰查詢(xún)敲茄,我們首先需要為數(shù)據(jù)創(chuàng)建一個(gè)Redisearch索引螺戳,其中包括一個(gè)用于存儲(chǔ)向量表示的字段。這些向量通常是由深度學(xué)習(xí)模型生成的高維數(shù)據(jù)表示折汞,可以捕捉數(shù)據(jù)之間的相似性。接下來(lái)盖腿,我們將使用自定義查詢(xún)函數(shù)爽待,結(jié)合Redisearch提供的搜索和排序功能,實(shí)現(xiàn)K近鄰查詢(xún)翩腐。
什么是文本向量表示?
文本向量表示是將自然語(yǔ)言文本轉(zhuǎn)換為固定長(zhǎng)度的數(shù)值向量鸟款。這些向量可以捕捉文本的語(yǔ)義信息,使得相似的文本具有相似的向量表示茂卦。文本向量通常是由諸如word2vec何什、GloVe、BERT等龙、GPT等預(yù)訓(xùn)練的神經(jīng)網(wǎng)絡(luò)模型生成的处渣。
以下是一個(gè)使用Gensim庫(kù)加載預(yù)訓(xùn)練的word2vec模型并獲取單詞“apple”的向量表示的示例:
import gensim.downloader as api
# 加載預(yù)訓(xùn)練的word2vec模型
model = api.load("word2vec-google-news-300")
# 獲取單詞"apple"的向量表示
word_vector = model["apple"]
# 輸出向量表示
print(word_vector)
輸出示例(前10個(gè)數(shù)值):
[ 0.10644531 0.04785156 -0.02258301 -0.06225586 0.01318359 0.05834961 -0.07666016 0.01525879 0.02563477 -0.06787109 ...]
請(qǐng)注意,實(shí)際的向量表示將包含300個(gè)浮點(diǎn)數(shù)值蛛砰,但這里僅顯示了前10個(gè)罐栈。這個(gè)向量表示捕捉了單詞“apple”的語(yǔ)義信息,可以用于文本相似性計(jì)算泥畅、文本分類(lèi)等自然語(yǔ)言處理任務(wù)荠诬。
文本向量怎么進(jìn)行對(duì)比?
通過(guò)比較兩個(gè)文本生成的向量位仁,我們可以衡量它們的語(yǔ)義相似性柑贞。通常,我們使用一種相似性度量方法來(lái)計(jì)算兩個(gè)向量之間的相似性得分聂抢。常用的相似性度量方法包括余弦相似性和歐幾里得距離钧嘶。
- 余弦相似性:余弦相似性衡量的是兩個(gè)向量之間的夾角的余弦值。它的取值范圍是[-1, 1]涛浙,值越接近1康辑,表示向量越相似;值越接近-1轿亮,表示向量越不相似疮薇。余弦相似性計(jì)算公式如下:
cos_sim(A, B) = dot_product(A, B) / (norm(A) * norm(B))
其中,dot_product(A, B)表示向量A和向量B的點(diǎn)積我注,norm(A)表示向量A的模長(zhǎng)按咒。
-
歐幾里得距離:歐幾里得距離衡量的是兩個(gè)向量在空間中的直線(xiàn)距離。數(shù)值越小,表示兩個(gè)向量越相似励七。歐幾里得距離計(jì)算公式如下:
euclidean_distance(A, B) = sqrt(sum((A_i - B_i)^2 for i in range(len(A))))
其中智袭,A_i和B_i分別表示向量A和向量B的第i個(gè)分量。
通過(guò)計(jì)算文本向量之間的相似性得分掠抬,我們可以確定哪些文本在語(yǔ)義上更相似吼野。這種方法可以用于許多自然語(yǔ)言處理任務(wù),如文本聚類(lèi)两波、文檔檢索和推薦系統(tǒng)等瞳步。
如何使用Redisearch實(shí)現(xiàn)K近鄰查詢(xún)
在這一部分,我們將詳細(xì)說(shuō)明如何使用Redisearch實(shí)現(xiàn)K近鄰查詢(xún)腰奋。主要分為以下幾個(gè)步驟:
1. 安裝Redisearch模塊并啟用单起。
2. 為數(shù)據(jù)創(chuàng)建一個(gè)Redisearch索引,包括一個(gè)用于存儲(chǔ)向量表示的字段劣坊。
3. 使用深度學(xué)習(xí)模型(如BERT嘀倒、Word2Vec等)為數(shù)據(jù)生成向量表示,并將它們存儲(chǔ)在Redisearch索引中局冰。
4. 構(gòu)建一個(gè)自定義查詢(xún)字符串测蘑,用于執(zhí)行K近鄰查詢(xún)。
5. 使用Redisearch的搜索和排序功能康二,根據(jù)查詢(xún)向量找到最相關(guān)的數(shù)據(jù)帮寻。
1. 安裝Redisearch模塊并啟用
要使用Redisearch,您需要安裝并啟用Redisearch模塊赠摇。有關(guān)詳細(xì)的安裝說(shuō)明固逗,請(qǐng)參閱Redisearch官方文檔:安裝Redisearch。
2. 為數(shù)據(jù)創(chuàng)建Redisearch索引
創(chuàng)建Redisearch索引的語(yǔ)法如下:
FT.CREATE {index_name} [NOOFFSETS] [NOFIELDS] [NOSCOREIDX] [STOPWORDS {num}] [SCHEMA {field_name} {type} [options] ...]
在我們的例子中藕帜,假設(shè)我們有一組文本數(shù)據(jù)烫罩,我們想要根據(jù)它們的向量表示執(zhí)行K近鄰查詢(xún)。我們可以創(chuàng)建一個(gè)包含text
和embedding
字段的索引:
FT.CREATE myindex SCHEMA text TEXT embedding VECTOR
3. 生成向量表示并將其存儲(chǔ)在Redisearch索引中
為了計(jì)算文本數(shù)據(jù)的向量表示洽故,您需要選擇一個(gè)合適的深度學(xué)習(xí)模型贝攒,如BERT、Word2Vec或GPT时甚。然后隘弊,您可以使用這些模型將文本轉(zhuǎn)換為高維向量。
以BERT模型為例荒适,您可以使用huggingface/transformers庫(kù)為文本生成向量表示梨熙。將向量表示存儲(chǔ)在Redisearch索引中的示例代碼如下:
import redis
from transformers import AutoTokenizer, AutoModel
# 初始化BERT模型和tokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
model = AutoModel.from_pretrained("bert-base-uncased")
# 準(zhǔn)備文本數(shù)據(jù)
text = "This is an example sentence."
# 使用tokenizer將文本轉(zhuǎn)換為token
tokens = tokenizer(text, return_tensors="pt")
# 使用BERT模型為文本生成向量表示
embeddings = model(**tokens).last_hidden_state.mean(dim=1).squeeze().tolist()
# 連接Redis,并將文本和embeddings存儲(chǔ)在索引中
r = redis.StrictRedis()
r.execute_command("FT.ADD", "myindex", "doc1", "1.0", "FIELDS", "text", text, "embedding", ",".join(map(str, embeddings)))
4. 構(gòu)建自定義查詢(xún)字符串
為了執(zhí)行K近鄰查詢(xún)刀诬,我們需要構(gòu)建一個(gè)自定義查詢(xún)字符串咽扇。在這個(gè)例子中,我們使用了如下格式的查詢(xún)字符串:
"*=>[KNN {num_relevant} @embedding $vector AS vector_score]"
其中,num_relevant
是我們想要返回的最相關(guān)結(jié)果的數(shù)量质欲,$vector
是我們想要與索引中的數(shù)據(jù)進(jìn)行比較的查詢(xún)向量树埠。
在查詢(xún)字符串中,*
表示搜索所有文檔嘶伟,=>
是一個(gè)映射操作符怎憋,用于將輸入文檔映射到新的搜索結(jié)果。KNN
是一個(gè)特殊的聚合函數(shù)九昧,用于計(jì)算查詢(xún)向量與索引中文檔的向量之間的相似度盛霎。@embedding
表示我們要使用索引中的embedding
字段作為向量。AS vector_score
表示將每個(gè)文檔的相似度得分存儲(chǔ)在名為vector_score
的字段中耽装。
案例分析:
*=>[KNN 5 @embedding $vector AS vector_score]
- 是一個(gè)通配符,表示返回所有文檔期揪。這是查詢(xún)的起點(diǎn)掉奄,之后會(huì)應(yīng)用其他過(guò)濾器或函數(shù)。
- => 是一個(gè)箭頭操作符凤薛,它用于將查詢(xún)結(jié)果傳遞給下一個(gè)步驟姓建。在這里,它將所有文檔傳遞給
[KNN 5 @embedding $vector AS vector_score]
函數(shù)缤苫。 -
[KNN 5 @embedding $vector AS vector_score]
是一個(gè)自定義函數(shù)速兔,它的目的是對(duì)所有文檔進(jìn)行排序,以便返回最相關(guān)的結(jié)果活玲。這個(gè)函數(shù)有以下參數(shù):-
KNN 5
表示返回與查詢(xún)向量最接近的5個(gè)文檔涣狗。 -
@embedding
是Redisearch索引中的字段名,用于存儲(chǔ)嵌入向量舒憾。 -
$vector
是傳遞給查詢(xún)的參數(shù)镀钓,表示要與文檔中的向量進(jìn)行比較的向量。 -
AS vector_score
表示將排序結(jié)果的分?jǐn)?shù)(相關(guān)性度量)存儲(chǔ)在名為vector_score
的字段中镀迂。
-
實(shí)際上丁溅,base_query字符串并不是固定的。您可以根據(jù)需要修改查詢(xún)字符串探遵,以適應(yīng)您的應(yīng)用程序需求窟赏。例如,您可以更改KNN參數(shù)以返回更多或更少的相關(guān)結(jié)果箱季。但請(qǐng)注意涯穷,修改查詢(xún)字符串可能會(huì)影響查詢(xún)的結(jié)果和性能。
5. 使用Redisearch搜索和排序功能執(zhí)行K近鄰查詢(xún)
最后藏雏,我們可以使用Redisearch的搜索和排序功能執(zhí)行K近鄰查詢(xún)求豫。以下是一個(gè)示例Python代碼:
from redisearch import Client, Query
def knn_search(query_vector, num_relevant=5):
# 創(chuàng)建Redisearch客戶(hù)端
client = Client("myindex")
# 構(gòu)建基本查詢(xún)字符串
base_query = f"*=>[KNN {num_relevant} @embedding $vector AS vector_score]"
# 使用Query類(lèi)構(gòu)建查詢(xún)
query = Query(base_query).return_fields("text", "vector_score").sort_by("vector_score").dialect(2)
# 將查詢(xún)向量轉(zhuǎn)換為字符串
query_vector_str = ",".join(map(str, query_vector))
# 執(zhí)行查詢(xún),并將查詢(xún)向量傳遞給Redisearch
results = client.search(query, query_params={"vector": query_vector_str})
# 返回查詢(xún)結(jié)果
return results
# 示例查詢(xún)向量
example_query_vector = [0.1, 0.2, 0.3, 0.4, 0.5]
# 執(zhí)行K近鄰查詢(xún)
result = knn_search(example_query_vector)
# 打印查詢(xún)結(jié)果
print(result)
這個(gè)示例代碼首先創(chuàng)建了一個(gè)Client
對(duì)象,用于與Redisearch
索引進(jìn)行通信蝠嘉。然后最疆,我們使用Query
類(lèi)構(gòu)建查詢(xún),并指定要返回的字段(text
和vector_score
)以及按照相似度得分(vector_score
)排序蚤告。最后努酸,我們使用client.search()
方法執(zhí)行查詢(xún),并將查詢(xún)向量傳遞給Redisearch杜恰。
這樣获诈,我們就完成了使用Redisearch實(shí)現(xiàn)K近鄰查詢(xún)的過(guò)程。