组合查询
组合查询表达式
组合查询是几种查询类型的组合,例如
您可以使用逻辑查询运算符来组合数值、标签和文本字段的查询表达式。对于向量字段,您可以将 KNN 查询与预过滤器结合使用。
本文中的示例使用以下 schema
字段名 | 字段类型 |
---|---|
description |
TEXT |
condition |
TAG |
price |
NUMERIC |
vector |
VECTOR |
AND
二元运算符
(空格)用于计算两个或多个表达式结果的交集。
FT.SEARCH index "(expr1) (expr2)"
如果您想基于特定文本字段中的多个值执行交集运算,则应使用以下简化表示法
FT.SEARCH index "@text_field:( value1 value2 ... )"
以下示例展示了一个查询,该查询查找处于新状态且价格范围在 500 美元到 1000 美元之间的自行车
FT.SEARCH idx:bicycle "@price:[500 1000] @condition:{new}"
厌倦了使用 redis-cli?试试 Redis Insight - Redis 开发者 GUI。
import json
import numpy as np
import redis
import warnings
from redis.commands.json.path import Path
from redis.commands.search.field import NumericField, TagField, TextField, VectorField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
from sentence_transformers import SentenceTransformer
def embed_text(model, text):
return np.array(model.encode(text)).astype(np.float32).tobytes()
warnings.filterwarnings("ignore", category=FutureWarning, message=r".*clean_up_tokenization_spaces.*")
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
query = "Bike for small kids"
query_vector = embed_text(model, query)
r = redis.Redis(decode_responses=True)
# create index
schema = (
TextField("$.description", no_stem=True, as_name="model"),
TagField("$.condition", as_name="condition"),
NumericField("$.price", as_name="price"),
VectorField(
"$.description_embeddings",
"FLAT",
{
"TYPE": "FLOAT32",
"DIM": 384,
"DISTANCE_METRIC": "COSINE",
},
as_name="vector",
),
)
index = r.ft("idx:bicycle")
index.create_index(
schema,
definition=IndexDefinition(prefix=["bicycle:"], index_type=IndexType.JSON),
)
# load data
with open("data/query_vector.json") as f:
bicycles = json.load(f)
pipeline = r.pipeline(transaction=False)
for bid, bicycle in enumerate(bicycles):
pipeline.json().set(f'bicycle:{bid}', Path.root_path(), bicycle)
pipeline.execute()
q = Query("@price:[500 1000] @condition:{new}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("kids @price:[500 1000] @condition:{used}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("@description:(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@description:(kids | small) @condition:{new | used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@price:[500 1000] -@condition:{new}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]").dialect(2)
# put query string here
res = index.search(q,{ 'query_vector': query_vector })
print(res.total) # >>> 2
import assert from 'node:assert';
import fs from 'node:fs';
import { createClient } from 'redis';
import { SchemaFieldTypes, VectorAlgorithms } from '@redis/search';
import { pipeline } from '@xenova/transformers';
function float32Buffer(arr) {
const floatArray = new Float32Array(arr);
const float32Buffer = Buffer.from(floatArray.buffer);
return float32Buffer;
}
async function embedText(sentence) {
let modelName = 'Xenova/all-MiniLM-L6-v2';
let pipe = await pipeline('feature-extraction', modelName);
let vectorOutput = await pipe(sentence, {
pooling: 'mean',
normalize: true,
});
if (vectorOutput == null) {
throw new Error('vectorOutput is undefined');
}
const embedding = Object.values(vectorOutput.data);
return embedding;
}
let query = 'Bike for small kids';
let vector_query = float32Buffer(await embedText('That is a very happy person'));
const client = createClient();
await client.connect().catch(console.error);
// create index
await client.ft.create('idx:bicycle', {
'$.description': {
type: SchemaFieldTypes.TEXT,
AS: 'description'
},
'$.condition': {
type: SchemaFieldTypes.TAG,
AS: 'condition'
},
'$.price': {
type: SchemaFieldTypes.NUMERIC,
AS: 'price'
},
'$.description_embeddings': {
type: SchemaFieldTypes.VECTOR,
TYPE: 'FLOAT32',
ALGORITHM: VectorAlgorithms.FLAT,
DIM: 384,
DISTANCE_METRIC: 'COSINE',
AS: 'vector',
}
}, {
ON: 'JSON',
PREFIX: 'bicycle:'
});
// load data
const bicycles = JSON.parse(fs.readFileSync('data/query_vector.json', 'utf8'));
await Promise.all(
bicycles.map((bicycle, bid) => {
return client.json.set(`bicycle:${bid}`, '$', bicycle);
})
);
const res1 = await client.ft.search('idx:bicycle', '@price:[500 1000] @condition:{new}');
console.log(res1.total); // >>> 1
console.log(res1); // >>>
//{
// total: 1,
// documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]
//}
const res2 = await client.ft.search('idx:bicycle', 'kids @price:[500 1000] @condition:{used}');
console.log(res2.total); // >>> 1
console.log(res2); // >>>
// {
// total: 1,
// documents: [ { id: 'bicycle:2', value: [Object: null prototype] } ]
// }
const res3 = await client.ft.search('idx:bicycle', '(kids | small) @condition:{used}');
console.log(res3.total); // >>> 2
console.log(res3); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res4 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{used}');
console.log(res4.total); // >>> 2
console.log(res4); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res5 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{new | used}');
console.log(res5.total); // >>> 3
console.log(res5); // >>>
//{
// total: 3,
// documents: [
// { id: 'bicycle:1', value: [Object: null prototype] },
// { id: 'bicycle:0', value: [Object: null prototype] },
// { id: 'bicycle:2', value: [Object: null prototype] }
// ]
//}
const res6 = await client.ft.search('idx:bicycle', '@price:[500 1000] -@condition:{new}');
console.log(res6.total); // >>> 2
console.log(res6); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
const res7 = await client.ft.search('idx:bicycle',
'(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]', {
PARAMS: { query_vector: vector_query },
DIALECT: 2
}
);
console.log(res7.total); // >>> 2
console.log(res7); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
您可能也对儿童自行车感兴趣。以下查询展示了如何将全文搜索与上一个查询的条件结合使用
FT.SEARCH idx:bicycle "kids (@price:[500 1000] @condition:{used})"
厌倦了使用 redis-cli?试试 Redis Insight - Redis 开发者 GUI。
import json
import numpy as np
import redis
import warnings
from redis.commands.json.path import Path
from redis.commands.search.field import NumericField, TagField, TextField, VectorField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
from sentence_transformers import SentenceTransformer
def embed_text(model, text):
return np.array(model.encode(text)).astype(np.float32).tobytes()
warnings.filterwarnings("ignore", category=FutureWarning, message=r".*clean_up_tokenization_spaces.*")
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
query = "Bike for small kids"
query_vector = embed_text(model, query)
r = redis.Redis(decode_responses=True)
# create index
schema = (
TextField("$.description", no_stem=True, as_name="model"),
TagField("$.condition", as_name="condition"),
NumericField("$.price", as_name="price"),
VectorField(
"$.description_embeddings",
"FLAT",
{
"TYPE": "FLOAT32",
"DIM": 384,
"DISTANCE_METRIC": "COSINE",
},
as_name="vector",
),
)
index = r.ft("idx:bicycle")
index.create_index(
schema,
definition=IndexDefinition(prefix=["bicycle:"], index_type=IndexType.JSON),
)
# load data
with open("data/query_vector.json") as f:
bicycles = json.load(f)
pipeline = r.pipeline(transaction=False)
for bid, bicycle in enumerate(bicycles):
pipeline.json().set(f'bicycle:{bid}', Path.root_path(), bicycle)
pipeline.execute()
q = Query("@price:[500 1000] @condition:{new}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("kids @price:[500 1000] @condition:{used}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("@description:(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@description:(kids | small) @condition:{new | used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@price:[500 1000] -@condition:{new}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]").dialect(2)
# put query string here
res = index.search(q,{ 'query_vector': query_vector })
print(res.total) # >>> 2
import assert from 'node:assert';
import fs from 'node:fs';
import { createClient } from 'redis';
import { SchemaFieldTypes, VectorAlgorithms } from '@redis/search';
import { pipeline } from '@xenova/transformers';
function float32Buffer(arr) {
const floatArray = new Float32Array(arr);
const float32Buffer = Buffer.from(floatArray.buffer);
return float32Buffer;
}
async function embedText(sentence) {
let modelName = 'Xenova/all-MiniLM-L6-v2';
let pipe = await pipeline('feature-extraction', modelName);
let vectorOutput = await pipe(sentence, {
pooling: 'mean',
normalize: true,
});
if (vectorOutput == null) {
throw new Error('vectorOutput is undefined');
}
const embedding = Object.values(vectorOutput.data);
return embedding;
}
let query = 'Bike for small kids';
let vector_query = float32Buffer(await embedText('That is a very happy person'));
const client = createClient();
await client.connect().catch(console.error);
// create index
await client.ft.create('idx:bicycle', {
'$.description': {
type: SchemaFieldTypes.TEXT,
AS: 'description'
},
'$.condition': {
type: SchemaFieldTypes.TAG,
AS: 'condition'
},
'$.price': {
type: SchemaFieldTypes.NUMERIC,
AS: 'price'
},
'$.description_embeddings': {
type: SchemaFieldTypes.VECTOR,
TYPE: 'FLOAT32',
ALGORITHM: VectorAlgorithms.FLAT,
DIM: 384,
DISTANCE_METRIC: 'COSINE',
AS: 'vector',
}
}, {
ON: 'JSON',
PREFIX: 'bicycle:'
});
// load data
const bicycles = JSON.parse(fs.readFileSync('data/query_vector.json', 'utf8'));
await Promise.all(
bicycles.map((bicycle, bid) => {
return client.json.set(`bicycle:${bid}`, '$', bicycle);
})
);
const res1 = await client.ft.search('idx:bicycle', '@price:[500 1000] @condition:{new}');
console.log(res1.total); // >>> 1
console.log(res1); // >>>
//{
// total: 1,
// documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]
//}
const res2 = await client.ft.search('idx:bicycle', 'kids @price:[500 1000] @condition:{used}');
console.log(res2.total); // >>> 1
console.log(res2); // >>>
// {
// total: 1,
// documents: [ { id: 'bicycle:2', value: [Object: null prototype] } ]
// }
const res3 = await client.ft.search('idx:bicycle', '(kids | small) @condition:{used}');
console.log(res3.total); // >>> 2
console.log(res3); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res4 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{used}');
console.log(res4.total); // >>> 2
console.log(res4); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res5 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{new | used}');
console.log(res5.total); // >>> 3
console.log(res5); // >>>
//{
// total: 3,
// documents: [
// { id: 'bicycle:1', value: [Object: null prototype] },
// { id: 'bicycle:0', value: [Object: null prototype] },
// { id: 'bicycle:2', value: [Object: null prototype] }
// ]
//}
const res6 = await client.ft.search('idx:bicycle', '@price:[500 1000] -@condition:{new}');
console.log(res6.total); // >>> 2
console.log(res6); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
const res7 = await client.ft.search('idx:bicycle',
'(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]', {
PARAMS: { query_vector: vector_query },
DIALECT: 2
}
);
console.log(res7.total); // >>> 2
console.log(res7); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
OR
您可以使用二元运算符 |
(竖线)执行联合运算。
FT.SEARCH index "(expr1) | (expr2)"
注意
使用方言版本二时,逻辑 AND
优先于 OR
。表达式 expr1 expr2 | expr3 expr4
表示 (expr1 expr2) | (expr3 expr4)
。查询方言版本一的行为方式不同。建议在查询字符串中使用括号以确保顺序清晰。如果您想基于单个标签或文本字段中的多个值执行联合运算,则应使用以下简化表示法
FT.SEARCH index "@text_field:( value1 | value2 | ... )"
FT.SEARCH index "@tag_field:{ value1 | value2 | ... }"
以下查询展示了如何查找包含单词 'kids' 或 'small' 的二手自行车
FT.SEARCH idx:bicycle "(kids | small) @condition:{used}"
厌倦了使用 redis-cli?试试 Redis Insight - Redis 开发者 GUI。
import json
import numpy as np
import redis
import warnings
from redis.commands.json.path import Path
from redis.commands.search.field import NumericField, TagField, TextField, VectorField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
from sentence_transformers import SentenceTransformer
def embed_text(model, text):
return np.array(model.encode(text)).astype(np.float32).tobytes()
warnings.filterwarnings("ignore", category=FutureWarning, message=r".*clean_up_tokenization_spaces.*")
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
query = "Bike for small kids"
query_vector = embed_text(model, query)
r = redis.Redis(decode_responses=True)
# create index
schema = (
TextField("$.description", no_stem=True, as_name="model"),
TagField("$.condition", as_name="condition"),
NumericField("$.price", as_name="price"),
VectorField(
"$.description_embeddings",
"FLAT",
{
"TYPE": "FLOAT32",
"DIM": 384,
"DISTANCE_METRIC": "COSINE",
},
as_name="vector",
),
)
index = r.ft("idx:bicycle")
index.create_index(
schema,
definition=IndexDefinition(prefix=["bicycle:"], index_type=IndexType.JSON),
)
# load data
with open("data/query_vector.json") as f:
bicycles = json.load(f)
pipeline = r.pipeline(transaction=False)
for bid, bicycle in enumerate(bicycles):
pipeline.json().set(f'bicycle:{bid}', Path.root_path(), bicycle)
pipeline.execute()
q = Query("@price:[500 1000] @condition:{new}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("kids @price:[500 1000] @condition:{used}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("@description:(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@description:(kids | small) @condition:{new | used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@price:[500 1000] -@condition:{new}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]").dialect(2)
# put query string here
res = index.search(q,{ 'query_vector': query_vector })
print(res.total) # >>> 2
import assert from 'node:assert';
import fs from 'node:fs';
import { createClient } from 'redis';
import { SchemaFieldTypes, VectorAlgorithms } from '@redis/search';
import { pipeline } from '@xenova/transformers';
function float32Buffer(arr) {
const floatArray = new Float32Array(arr);
const float32Buffer = Buffer.from(floatArray.buffer);
return float32Buffer;
}
async function embedText(sentence) {
let modelName = 'Xenova/all-MiniLM-L6-v2';
let pipe = await pipeline('feature-extraction', modelName);
let vectorOutput = await pipe(sentence, {
pooling: 'mean',
normalize: true,
});
if (vectorOutput == null) {
throw new Error('vectorOutput is undefined');
}
const embedding = Object.values(vectorOutput.data);
return embedding;
}
let query = 'Bike for small kids';
let vector_query = float32Buffer(await embedText('That is a very happy person'));
const client = createClient();
await client.connect().catch(console.error);
// create index
await client.ft.create('idx:bicycle', {
'$.description': {
type: SchemaFieldTypes.TEXT,
AS: 'description'
},
'$.condition': {
type: SchemaFieldTypes.TAG,
AS: 'condition'
},
'$.price': {
type: SchemaFieldTypes.NUMERIC,
AS: 'price'
},
'$.description_embeddings': {
type: SchemaFieldTypes.VECTOR,
TYPE: 'FLOAT32',
ALGORITHM: VectorAlgorithms.FLAT,
DIM: 384,
DISTANCE_METRIC: 'COSINE',
AS: 'vector',
}
}, {
ON: 'JSON',
PREFIX: 'bicycle:'
});
// load data
const bicycles = JSON.parse(fs.readFileSync('data/query_vector.json', 'utf8'));
await Promise.all(
bicycles.map((bicycle, bid) => {
return client.json.set(`bicycle:${bid}`, '$', bicycle);
})
);
const res1 = await client.ft.search('idx:bicycle', '@price:[500 1000] @condition:{new}');
console.log(res1.total); // >>> 1
console.log(res1); // >>>
//{
// total: 1,
// documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]
//}
const res2 = await client.ft.search('idx:bicycle', 'kids @price:[500 1000] @condition:{used}');
console.log(res2.total); // >>> 1
console.log(res2); // >>>
// {
// total: 1,
// documents: [ { id: 'bicycle:2', value: [Object: null prototype] } ]
// }
const res3 = await client.ft.search('idx:bicycle', '(kids | small) @condition:{used}');
console.log(res3.total); // >>> 2
console.log(res3); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res4 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{used}');
console.log(res4.total); // >>> 2
console.log(res4); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res5 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{new | used}');
console.log(res5.total); // >>> 3
console.log(res5); // >>>
//{
// total: 3,
// documents: [
// { id: 'bicycle:1', value: [Object: null prototype] },
// { id: 'bicycle:0', value: [Object: null prototype] },
// { id: 'bicycle:2', value: [Object: null prototype] }
// ]
//}
const res6 = await client.ft.search('idx:bicycle', '@price:[500 1000] -@condition:{new}');
console.log(res6.total); // >>> 2
console.log(res6); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
const res7 = await client.ft.search('idx:bicycle',
'(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]', {
PARAMS: { query_vector: vector_query },
DIALECT: 2
}
);
console.log(res7.total); // >>> 2
console.log(res7); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
上一个查询搜索所有文本字段。以下示例展示了如何将搜索限制在 description 字段
FT.SEARCH idx:bicycle "@description:(kids | small) @condition:{used}"
厌倦了使用 redis-cli?试试 Redis Insight - Redis 开发者 GUI。
import json
import numpy as np
import redis
import warnings
from redis.commands.json.path import Path
from redis.commands.search.field import NumericField, TagField, TextField, VectorField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
from sentence_transformers import SentenceTransformer
def embed_text(model, text):
return np.array(model.encode(text)).astype(np.float32).tobytes()
warnings.filterwarnings("ignore", category=FutureWarning, message=r".*clean_up_tokenization_spaces.*")
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
query = "Bike for small kids"
query_vector = embed_text(model, query)
r = redis.Redis(decode_responses=True)
# create index
schema = (
TextField("$.description", no_stem=True, as_name="model"),
TagField("$.condition", as_name="condition"),
NumericField("$.price", as_name="price"),
VectorField(
"$.description_embeddings",
"FLAT",
{
"TYPE": "FLOAT32",
"DIM": 384,
"DISTANCE_METRIC": "COSINE",
},
as_name="vector",
),
)
index = r.ft("idx:bicycle")
index.create_index(
schema,
definition=IndexDefinition(prefix=["bicycle:"], index_type=IndexType.JSON),
)
# load data
with open("data/query_vector.json") as f:
bicycles = json.load(f)
pipeline = r.pipeline(transaction=False)
for bid, bicycle in enumerate(bicycles):
pipeline.json().set(f'bicycle:{bid}', Path.root_path(), bicycle)
pipeline.execute()
q = Query("@price:[500 1000] @condition:{new}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("kids @price:[500 1000] @condition:{used}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("@description:(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@description:(kids | small) @condition:{new | used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@price:[500 1000] -@condition:{new}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]").dialect(2)
# put query string here
res = index.search(q,{ 'query_vector': query_vector })
print(res.total) # >>> 2
import assert from 'node:assert';
import fs from 'node:fs';
import { createClient } from 'redis';
import { SchemaFieldTypes, VectorAlgorithms } from '@redis/search';
import { pipeline } from '@xenova/transformers';
function float32Buffer(arr) {
const floatArray = new Float32Array(arr);
const float32Buffer = Buffer.from(floatArray.buffer);
return float32Buffer;
}
async function embedText(sentence) {
let modelName = 'Xenova/all-MiniLM-L6-v2';
let pipe = await pipeline('feature-extraction', modelName);
let vectorOutput = await pipe(sentence, {
pooling: 'mean',
normalize: true,
});
if (vectorOutput == null) {
throw new Error('vectorOutput is undefined');
}
const embedding = Object.values(vectorOutput.data);
return embedding;
}
let query = 'Bike for small kids';
let vector_query = float32Buffer(await embedText('That is a very happy person'));
const client = createClient();
await client.connect().catch(console.error);
// create index
await client.ft.create('idx:bicycle', {
'$.description': {
type: SchemaFieldTypes.TEXT,
AS: 'description'
},
'$.condition': {
type: SchemaFieldTypes.TAG,
AS: 'condition'
},
'$.price': {
type: SchemaFieldTypes.NUMERIC,
AS: 'price'
},
'$.description_embeddings': {
type: SchemaFieldTypes.VECTOR,
TYPE: 'FLOAT32',
ALGORITHM: VectorAlgorithms.FLAT,
DIM: 384,
DISTANCE_METRIC: 'COSINE',
AS: 'vector',
}
}, {
ON: 'JSON',
PREFIX: 'bicycle:'
});
// load data
const bicycles = JSON.parse(fs.readFileSync('data/query_vector.json', 'utf8'));
await Promise.all(
bicycles.map((bicycle, bid) => {
return client.json.set(`bicycle:${bid}`, '$', bicycle);
})
);
const res1 = await client.ft.search('idx:bicycle', '@price:[500 1000] @condition:{new}');
console.log(res1.total); // >>> 1
console.log(res1); // >>>
//{
// total: 1,
// documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]
//}
const res2 = await client.ft.search('idx:bicycle', 'kids @price:[500 1000] @condition:{used}');
console.log(res2.total); // >>> 1
console.log(res2); // >>>
// {
// total: 1,
// documents: [ { id: 'bicycle:2', value: [Object: null prototype] } ]
// }
const res3 = await client.ft.search('idx:bicycle', '(kids | small) @condition:{used}');
console.log(res3.total); // >>> 2
console.log(res3); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res4 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{used}');
console.log(res4.total); // >>> 2
console.log(res4); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res5 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{new | used}');
console.log(res5.total); // >>> 3
console.log(res5); // >>>
//{
// total: 3,
// documents: [
// { id: 'bicycle:1', value: [Object: null prototype] },
// { id: 'bicycle:0', value: [Object: null prototype] },
// { id: 'bicycle:2', value: [Object: null prototype] }
// ]
//}
const res6 = await client.ft.search('idx:bicycle', '@price:[500 1000] -@condition:{new}');
console.log(res6.total); // >>> 2
console.log(res6); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
const res7 = await client.ft.search('idx:bicycle',
'(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]', {
PARAMS: { query_vector: vector_query },
DIALECT: 2
}
);
console.log(res7.total); // >>> 2
console.log(res7); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
如果您想将搜索扩展到新自行车,则以下示例展示了如何实现
FT.SEARCH idx:bicycle "@description:(kids | small) @condition:{new | used}"
厌倦了使用 redis-cli?试试 Redis Insight - Redis 开发者 GUI。
import json
import numpy as np
import redis
import warnings
from redis.commands.json.path import Path
from redis.commands.search.field import NumericField, TagField, TextField, VectorField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
from sentence_transformers import SentenceTransformer
def embed_text(model, text):
return np.array(model.encode(text)).astype(np.float32).tobytes()
warnings.filterwarnings("ignore", category=FutureWarning, message=r".*clean_up_tokenization_spaces.*")
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
query = "Bike for small kids"
query_vector = embed_text(model, query)
r = redis.Redis(decode_responses=True)
# create index
schema = (
TextField("$.description", no_stem=True, as_name="model"),
TagField("$.condition", as_name="condition"),
NumericField("$.price", as_name="price"),
VectorField(
"$.description_embeddings",
"FLAT",
{
"TYPE": "FLOAT32",
"DIM": 384,
"DISTANCE_METRIC": "COSINE",
},
as_name="vector",
),
)
index = r.ft("idx:bicycle")
index.create_index(
schema,
definition=IndexDefinition(prefix=["bicycle:"], index_type=IndexType.JSON),
)
# load data
with open("data/query_vector.json") as f:
bicycles = json.load(f)
pipeline = r.pipeline(transaction=False)
for bid, bicycle in enumerate(bicycles):
pipeline.json().set(f'bicycle:{bid}', Path.root_path(), bicycle)
pipeline.execute()
q = Query("@price:[500 1000] @condition:{new}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("kids @price:[500 1000] @condition:{used}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("@description:(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@description:(kids | small) @condition:{new | used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@price:[500 1000] -@condition:{new}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]").dialect(2)
# put query string here
res = index.search(q,{ 'query_vector': query_vector })
print(res.total) # >>> 2
import assert from 'node:assert';
import fs from 'node:fs';
import { createClient } from 'redis';
import { SchemaFieldTypes, VectorAlgorithms } from '@redis/search';
import { pipeline } from '@xenova/transformers';
function float32Buffer(arr) {
const floatArray = new Float32Array(arr);
const float32Buffer = Buffer.from(floatArray.buffer);
return float32Buffer;
}
async function embedText(sentence) {
let modelName = 'Xenova/all-MiniLM-L6-v2';
let pipe = await pipeline('feature-extraction', modelName);
let vectorOutput = await pipe(sentence, {
pooling: 'mean',
normalize: true,
});
if (vectorOutput == null) {
throw new Error('vectorOutput is undefined');
}
const embedding = Object.values(vectorOutput.data);
return embedding;
}
let query = 'Bike for small kids';
let vector_query = float32Buffer(await embedText('That is a very happy person'));
const client = createClient();
await client.connect().catch(console.error);
// create index
await client.ft.create('idx:bicycle', {
'$.description': {
type: SchemaFieldTypes.TEXT,
AS: 'description'
},
'$.condition': {
type: SchemaFieldTypes.TAG,
AS: 'condition'
},
'$.price': {
type: SchemaFieldTypes.NUMERIC,
AS: 'price'
},
'$.description_embeddings': {
type: SchemaFieldTypes.VECTOR,
TYPE: 'FLOAT32',
ALGORITHM: VectorAlgorithms.FLAT,
DIM: 384,
DISTANCE_METRIC: 'COSINE',
AS: 'vector',
}
}, {
ON: 'JSON',
PREFIX: 'bicycle:'
});
// load data
const bicycles = JSON.parse(fs.readFileSync('data/query_vector.json', 'utf8'));
await Promise.all(
bicycles.map((bicycle, bid) => {
return client.json.set(`bicycle:${bid}`, '$', bicycle);
})
);
const res1 = await client.ft.search('idx:bicycle', '@price:[500 1000] @condition:{new}');
console.log(res1.total); // >>> 1
console.log(res1); // >>>
//{
// total: 1,
// documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]
//}
const res2 = await client.ft.search('idx:bicycle', 'kids @price:[500 1000] @condition:{used}');
console.log(res2.total); // >>> 1
console.log(res2); // >>>
// {
// total: 1,
// documents: [ { id: 'bicycle:2', value: [Object: null prototype] } ]
// }
const res3 = await client.ft.search('idx:bicycle', '(kids | small) @condition:{used}');
console.log(res3.total); // >>> 2
console.log(res3); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res4 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{used}');
console.log(res4.total); // >>> 2
console.log(res4); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res5 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{new | used}');
console.log(res5.total); // >>> 3
console.log(res5); // >>>
//{
// total: 3,
// documents: [
// { id: 'bicycle:1', value: [Object: null prototype] },
// { id: 'bicycle:0', value: [Object: null prototype] },
// { id: 'bicycle:2', value: [Object: null prototype] }
// ]
//}
const res6 = await client.ft.search('idx:bicycle', '@price:[500 1000] -@condition:{new}');
console.log(res6.total); // >>> 2
console.log(res6); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
const res7 = await client.ft.search('idx:bicycle',
'(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]', {
PARAMS: { query_vector: vector_query },
DIALECT: 2
}
);
console.log(res7.total); // >>> 2
console.log(res7); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
NOT
查询表达式前的减号(-
)表示否定该表达式。
FT.SEARCH index "-(expr)"
如果您想从之前的价格范围内排除新自行车,可以使用此查询
FT.SEARCH idx:bicycle "@price:[500 1000] -@condition:{new}"
厌倦了使用 redis-cli?试试 Redis Insight - Redis 开发者 GUI。
import json
import numpy as np
import redis
import warnings
from redis.commands.json.path import Path
from redis.commands.search.field import NumericField, TagField, TextField, VectorField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
from sentence_transformers import SentenceTransformer
def embed_text(model, text):
return np.array(model.encode(text)).astype(np.float32).tobytes()
warnings.filterwarnings("ignore", category=FutureWarning, message=r".*clean_up_tokenization_spaces.*")
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
query = "Bike for small kids"
query_vector = embed_text(model, query)
r = redis.Redis(decode_responses=True)
# create index
schema = (
TextField("$.description", no_stem=True, as_name="model"),
TagField("$.condition", as_name="condition"),
NumericField("$.price", as_name="price"),
VectorField(
"$.description_embeddings",
"FLAT",
{
"TYPE": "FLOAT32",
"DIM": 384,
"DISTANCE_METRIC": "COSINE",
},
as_name="vector",
),
)
index = r.ft("idx:bicycle")
index.create_index(
schema,
definition=IndexDefinition(prefix=["bicycle:"], index_type=IndexType.JSON),
)
# load data
with open("data/query_vector.json") as f:
bicycles = json.load(f)
pipeline = r.pipeline(transaction=False)
for bid, bicycle in enumerate(bicycles):
pipeline.json().set(f'bicycle:{bid}', Path.root_path(), bicycle)
pipeline.execute()
q = Query("@price:[500 1000] @condition:{new}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("kids @price:[500 1000] @condition:{used}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("@description:(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@description:(kids | small) @condition:{new | used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@price:[500 1000] -@condition:{new}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]").dialect(2)
# put query string here
res = index.search(q,{ 'query_vector': query_vector })
print(res.total) # >>> 2
import assert from 'node:assert';
import fs from 'node:fs';
import { createClient } from 'redis';
import { SchemaFieldTypes, VectorAlgorithms } from '@redis/search';
import { pipeline } from '@xenova/transformers';
function float32Buffer(arr) {
const floatArray = new Float32Array(arr);
const float32Buffer = Buffer.from(floatArray.buffer);
return float32Buffer;
}
async function embedText(sentence) {
let modelName = 'Xenova/all-MiniLM-L6-v2';
let pipe = await pipeline('feature-extraction', modelName);
let vectorOutput = await pipe(sentence, {
pooling: 'mean',
normalize: true,
});
if (vectorOutput == null) {
throw new Error('vectorOutput is undefined');
}
const embedding = Object.values(vectorOutput.data);
return embedding;
}
let query = 'Bike for small kids';
let vector_query = float32Buffer(await embedText('That is a very happy person'));
const client = createClient();
await client.connect().catch(console.error);
// create index
await client.ft.create('idx:bicycle', {
'$.description': {
type: SchemaFieldTypes.TEXT,
AS: 'description'
},
'$.condition': {
type: SchemaFieldTypes.TAG,
AS: 'condition'
},
'$.price': {
type: SchemaFieldTypes.NUMERIC,
AS: 'price'
},
'$.description_embeddings': {
type: SchemaFieldTypes.VECTOR,
TYPE: 'FLOAT32',
ALGORITHM: VectorAlgorithms.FLAT,
DIM: 384,
DISTANCE_METRIC: 'COSINE',
AS: 'vector',
}
}, {
ON: 'JSON',
PREFIX: 'bicycle:'
});
// load data
const bicycles = JSON.parse(fs.readFileSync('data/query_vector.json', 'utf8'));
await Promise.all(
bicycles.map((bicycle, bid) => {
return client.json.set(`bicycle:${bid}`, '$', bicycle);
})
);
const res1 = await client.ft.search('idx:bicycle', '@price:[500 1000] @condition:{new}');
console.log(res1.total); // >>> 1
console.log(res1); // >>>
//{
// total: 1,
// documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]
//}
const res2 = await client.ft.search('idx:bicycle', 'kids @price:[500 1000] @condition:{used}');
console.log(res2.total); // >>> 1
console.log(res2); // >>>
// {
// total: 1,
// documents: [ { id: 'bicycle:2', value: [Object: null prototype] } ]
// }
const res3 = await client.ft.search('idx:bicycle', '(kids | small) @condition:{used}');
console.log(res3.total); // >>> 2
console.log(res3); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res4 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{used}');
console.log(res4.total); // >>> 2
console.log(res4); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res5 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{new | used}');
console.log(res5.total); // >>> 3
console.log(res5); // >>>
//{
// total: 3,
// documents: [
// { id: 'bicycle:1', value: [Object: null prototype] },
// { id: 'bicycle:0', value: [Object: null prototype] },
// { id: 'bicycle:2', value: [Object: null prototype] }
// ]
//}
const res6 = await client.ft.search('idx:bicycle', '@price:[500 1000] -@condition:{new}');
console.log(res6.total); // >>> 2
console.log(res6); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
const res7 = await client.ft.search('idx:bicycle',
'(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]', {
PARAMS: { query_vector: vector_query },
DIALECT: 2
}
);
console.log(res7.total); // >>> 2
console.log(res7); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
数值过滤器
FT.SEARCH 命令允许您将任何查询表达式与数值过滤器结合使用。
FT.SEARCH index "expr" FILTER numeric_field start end
请参阅范围查询文章了解更多关于数值范围查询和此类过滤器的信息。
KNN 向量查询的预过滤器
您可以在 KNN 向量查询中使用带有逻辑运算符的简单或更复杂的查询表达式作为预过滤器。
FT.SEARCH index "(filter_expr)=>[KNN num_neighbours @field $vector]" PARAMS 2 vector "binary_data" DIALECT 2
这是一个示例
FT.SEARCH idx:bikes_vss "(@price:[500 1000] @condition:{new})=>[KNN 3 @vector $query_vector]" PARAMS 2 "query_vector" "Z\xf8\x15:\xf23\xa1\xbfZ\x1dI>\r\xca9..." DIALECT 2
厌倦了使用 redis-cli?试试 Redis Insight - Redis 开发者 GUI。
import json
import numpy as np
import redis
import warnings
from redis.commands.json.path import Path
from redis.commands.search.field import NumericField, TagField, TextField, VectorField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
from sentence_transformers import SentenceTransformer
def embed_text(model, text):
return np.array(model.encode(text)).astype(np.float32).tobytes()
warnings.filterwarnings("ignore", category=FutureWarning, message=r".*clean_up_tokenization_spaces.*")
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
query = "Bike for small kids"
query_vector = embed_text(model, query)
r = redis.Redis(decode_responses=True)
# create index
schema = (
TextField("$.description", no_stem=True, as_name="model"),
TagField("$.condition", as_name="condition"),
NumericField("$.price", as_name="price"),
VectorField(
"$.description_embeddings",
"FLAT",
{
"TYPE": "FLOAT32",
"DIM": 384,
"DISTANCE_METRIC": "COSINE",
},
as_name="vector",
),
)
index = r.ft("idx:bicycle")
index.create_index(
schema,
definition=IndexDefinition(prefix=["bicycle:"], index_type=IndexType.JSON),
)
# load data
with open("data/query_vector.json") as f:
bicycles = json.load(f)
pipeline = r.pipeline(transaction=False)
for bid, bicycle in enumerate(bicycles):
pipeline.json().set(f'bicycle:{bid}', Path.root_path(), bicycle)
pipeline.execute()
q = Query("@price:[500 1000] @condition:{new}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("kids @price:[500 1000] @condition:{used}")
res = index.search(q)
print(res.total) # >>> 1
q = Query("(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("@description:(kids | small) @condition:{used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@description:(kids | small) @condition:{new | used}")
res = index.search(q)
print(res.total) # >>> 0
q = Query("@price:[500 1000] -@condition:{new}")
res = index.search(q)
print(res.total) # >>> 2
q = Query("(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]").dialect(2)
# put query string here
res = index.search(q,{ 'query_vector': query_vector })
print(res.total) # >>> 2
import assert from 'node:assert';
import fs from 'node:fs';
import { createClient } from 'redis';
import { SchemaFieldTypes, VectorAlgorithms } from '@redis/search';
import { pipeline } from '@xenova/transformers';
function float32Buffer(arr) {
const floatArray = new Float32Array(arr);
const float32Buffer = Buffer.from(floatArray.buffer);
return float32Buffer;
}
async function embedText(sentence) {
let modelName = 'Xenova/all-MiniLM-L6-v2';
let pipe = await pipeline('feature-extraction', modelName);
let vectorOutput = await pipe(sentence, {
pooling: 'mean',
normalize: true,
});
if (vectorOutput == null) {
throw new Error('vectorOutput is undefined');
}
const embedding = Object.values(vectorOutput.data);
return embedding;
}
let query = 'Bike for small kids';
let vector_query = float32Buffer(await embedText('That is a very happy person'));
const client = createClient();
await client.connect().catch(console.error);
// create index
await client.ft.create('idx:bicycle', {
'$.description': {
type: SchemaFieldTypes.TEXT,
AS: 'description'
},
'$.condition': {
type: SchemaFieldTypes.TAG,
AS: 'condition'
},
'$.price': {
type: SchemaFieldTypes.NUMERIC,
AS: 'price'
},
'$.description_embeddings': {
type: SchemaFieldTypes.VECTOR,
TYPE: 'FLOAT32',
ALGORITHM: VectorAlgorithms.FLAT,
DIM: 384,
DISTANCE_METRIC: 'COSINE',
AS: 'vector',
}
}, {
ON: 'JSON',
PREFIX: 'bicycle:'
});
// load data
const bicycles = JSON.parse(fs.readFileSync('data/query_vector.json', 'utf8'));
await Promise.all(
bicycles.map((bicycle, bid) => {
return client.json.set(`bicycle:${bid}`, '$', bicycle);
})
);
const res1 = await client.ft.search('idx:bicycle', '@price:[500 1000] @condition:{new}');
console.log(res1.total); // >>> 1
console.log(res1); // >>>
//{
// total: 1,
// documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]
//}
const res2 = await client.ft.search('idx:bicycle', 'kids @price:[500 1000] @condition:{used}');
console.log(res2.total); // >>> 1
console.log(res2); // >>>
// {
// total: 1,
// documents: [ { id: 'bicycle:2', value: [Object: null prototype] } ]
// }
const res3 = await client.ft.search('idx:bicycle', '(kids | small) @condition:{used}');
console.log(res3.total); // >>> 2
console.log(res3); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res4 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{used}');
console.log(res4.total); // >>> 2
console.log(res4); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:1', value: [Object: null prototype] }
// ]
//}
const res5 = await client.ft.search('idx:bicycle', '@description:(kids | small) @condition:{new | used}');
console.log(res5.total); // >>> 3
console.log(res5); // >>>
//{
// total: 3,
// documents: [
// { id: 'bicycle:1', value: [Object: null prototype] },
// { id: 'bicycle:0', value: [Object: null prototype] },
// { id: 'bicycle:2', value: [Object: null prototype] }
// ]
//}
const res6 = await client.ft.search('idx:bicycle', '@price:[500 1000] -@condition:{new}');
console.log(res6.total); // >>> 2
console.log(res6); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
const res7 = await client.ft.search('idx:bicycle',
'(@price:[500 1000] -@condition:{new})=>[KNN 3 @vector $query_vector]', {
PARAMS: { query_vector: vector_query },
DIALECT: 2
}
);
console.log(res7.total); // >>> 2
console.log(res7); // >>>
//{
// total: 2,
// documents: [
// { id: 'bicycle:2', value: [Object: null prototype] },
// { id: 'bicycle:9', value: [Object: null prototype] }
// ]
//}
向量搜索文章提供了关于向量查询的更多详细信息。