Синтаксическая ошибка поиска сходства векторов 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, поэтому вы получаете синтаксическую ошибку.

Надеюсь, это поможет!

Другие вопросы по тегам