Синтаксическая ошибка поиска сходства векторов Redis
В настоящее время я работаю над кэшированием моего чат-бота, чтобы использовать встроенный поиск по сходству Redis. Их библиотека node-redis предоставляет интерфейс для этого. А еще в LangchainJS есть опции для кеширования, но они не будут работать так, как мне нужно, потому что у меня уже есть вложения для сохранения и поиска, а класс Embedding не работает (может и может, но это будут костыли), поэтому я решил написать индивидуальное решение с node-redis. И вот проблема...
Здесь, в их документации , есть примеры работы с запросами KNN.FT.SEARCH idx "*=>[KNN 10 @vec $BLOB]" PARAMS 2 BLOB "\x12\xa9\xf5\x6c" DIALECT 2
и это работает (по крайней мере, нет ошибок), если я использую его в termila или RedisInsight, но когда я пытаюсь запустить этот запрос с помощью nodejs, он выдает ошибку[ErrorReply: Syntax error at offset 2 near > ]
async function searchSimilar(vector: number[]) {
const query = `* => [KNN 10 @embedding $BLOB]`;
const options = {
PARAMS: {
BLOB: Buffer.from(new Float32Array(vector).buffer),
DIALECT: 2,
},
};
const result = await client.ft.search("idx:answers", query, options);
return result;
}
Возможно, я не понял, как это работает... Вот пример того, как это работает в Langchain.
async similaritySearchVectorWithScore(query, k, filter) {
if (filter && this.filter) {
throw new Error("cannot provide both `filter` and `this.filter`");
}
const _filter = filter ?? this.filter;
const results = await this.redisClient.ft.search(this.indexName, ...this.buildQuery(query, k, _filter));
const result = [];
if (results.total) {
for (const res of results.documents) {
if (res.value) {
const document = res.value;
if (document.vector_score) {
result.push([
new Document({
pageContent: document[this.contentKey],
metadata: JSON.parse(this.unEscapeSpecialChars(document.metadata)),
}),
Number(document.vector_score),
]);
}
}
}
}
return result;
}
buildQuery(query, k, filter) {
const vectorScoreField = "vector_score";
let hybridFields = "*";
// if a filter is set, modify the hybrid query
if (filter && filter.length) {
// `filter` is a list of strings, then it's applied using the OR operator in the metadata key
// for example: filter = ['foo', 'bar'] => this will filter all metadata containing either 'foo' OR 'bar'
hybridFields = `@${this.metadataKey}:(${this.prepareFilter(filter)})`;
}
const baseQuery = `${hybridFields} => [KNN ${k} @${this.vectorKey} $vector AS ${vectorScoreField}]`;
const returnFields = [this.metadataKey, this.contentKey, vectorScoreField];
const options = {
PARAMS: {
vector: this.getFloat32Buffer(query),
},
RETURN: returnFields,
SORTBY: vectorScoreField,
DIALECT: 2,
LIMIT: {
from: 0,
size: k,
},
};
return [baseQuery, options];
}
getFloat32Buffer(vector) {
return Buffer.from(new Float32Array(vector).buffer);
}
Вот нашел еще один пример на Python и не могу понять, почему мой запрос не работает
def create_query(
return_fields: list,
search_type: str="KNN",
number_of_results: int=20,
vector_field_name: str="img_vector",
gender: t.Optional[str] = None,
category: t.Optional[str] = None
):
tag = "("
if gender:
tag += f"@gender:{{{gender}}}"
if category:
tag += f"@category:{{{category}}}"
tag += ")"
# if no tags are selected
if len(tag) < 3:
tag = "*"
base_query = f'{tag}=>[{search_type} {number_of_results} @{vector_field_name} $vec_param AS vector_score]'
return Query(base_query)\
.sort_by("vector_score")\
.paging(0, number_of_results)\
.return_fields(*return_fields)\
.dialect(2)
Я читал документацию, искал в Интернете, открывал проблемы и обсуждения на GitHub и исследовал сборку библиотек Node JS.
1 ответ
Взгляните на этот пример . Атрибут должен появляться сам по себе, а не как частьPARAMS
, который должен включать только параметры самого запроса (например,BLOB
в вашем примере).
В общем, вы прошлиDIALECT
в качестве параметра запроса (даже несмотря на то, что он там не используется), а сам разбор производился с использованием диалекта по умолчанию, который на данный момент равен 1 (можно изменить с помощьюFT.CONFIG SET DEFAULT_DIALECT <n>
). Поиск KNN недоступен на диалекте 1, поэтому вы получаете синтаксическую ошибку.
Надеюсь, это поможет!