精确匹配查询
执行简单的精确匹配查询
精确匹配查询可以选择所有在指定字段上与特定值相匹配的文档。
你可以对多种字段类型执行精确匹配查询,具体的查询语法取决于字段类型。
本文中的示例使用以下 schema:
| 字段名 | 字段类型 |
|---|---|
description |
TEXT |
condition |
TAG |
price |
NUMERIC |
你可以在 快速入门指南 中了解更多关于创建索引和加载示例数据的细节。
数值字段
在数值字段上执行精确匹配查询时,需要构造一个起始值和结束值相同的范围查询:
FT.SEARCH index "@field:[value value]"或FT.SEARCH index "@field:[value]" DIALECT 2 # 需要 v2.10或FT.SEARCH index "@field==value" DIALECT 2 # 需要 v2.10
如在 范围查询文章 中描述的,你还可以使用 FILTER 参数:
FT.SEARCH index "*" FILTER field start end
以下示例展示了如何查询价格恰好为 270 美元的自行车:
_ Redis CLI
> FT.SEARCH idx:bicycle "@price:[270 270]"1) (integer) 12) "bicycle:0"3) 1) "$"2) "{\"pickup_zone\":\"POLYGON((-74.0610 40.7578, ..."> FT.SEARCH idx:bicycle "@price:[270]" # 需要 v2.101) (integer) 12) "bicycle:0"3) 1) "$"2) "{\"pickup_zone\":\"POLYGON((-74.0610 40.7578, ..."> FT.SEARCH idx:bicycle "@price==270" # 需要 v2.101) (integer) 12) "bicycle:0"3) 1) "$"2) "{\"pickup_zone\":\"POLYGON((-74.0610 40.7578, ..."> FT.SEARCH idx:bicycle "*" FILTER price 270 2701) (integer) 12) "bicycle:0"3) 1) "$"2) "{\"pickup_zone\":\"POLYGON((-74.0610 40.7578, ..."
✅ 提示:厌倦了使用 redis-cli?试试 Redis Insight —— 专为 Redis 开发者设计的图形化界面。
Python
import jsonimport redisfrom redis.commands.json.path import Pathfrom redis.commands.search.field import TextField, NumericField, TagFieldfrom redis.commands.search.indexDefinition import IndexDefinition, IndexTypefrom redis.commands.search.query import NumericFilter, Queryr = redis.Redis(decode_responses=True)# create indexschema = (TextField("$.description", as_name="description"),NumericField("$.price", as_name="price"),TagField("$.condition", as_name="condition"),)index = r.ft("idx:bicycle")index.create_index(schema,definition=IndexDefinition(prefix=["bicycle:"], index_type=IndexType.JSON),)# load datawith open("data/query_em.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()res = index.search(Query("@price:[270 270]"))print(res.total)# >>> 1try:res = index.search(Query("@price:[270]")) # not yet supported in redis-pyprint(res.total)# >>> 1assert res.total == 1except:print("'@price:[270]' syntax not yet supported.")try:res = index.search(Query("@price==270")) # not yet supported in redis-pyprint(res.total)# >>> 1assert res.total == 1except:print("'@price==270' syntax not yet supported.")query = Query("*").add_filter(NumericFilter("price", 270, 270))res = index.search(query)print(res.total)# >>> 1res = index.search(Query("@condition:{new}"))print(res.total)# >>> 5schema = (TagField("$.email", as_name="email"))idx_email = r.ft("idx:email")idx_email.create_index(schema,definition=IndexDefinition(prefix=["key:"], index_type=IndexType.JSON),)r.json().set('key:1', Path.root_path(), '{"email": "test@redis.com"}')try:res = idx_email.search(Query("test@redis.com").dialect(2))print(res)except:print("'test@redis.com' syntax not yet supported.")res = index.search(Query("@description:\"rough terrain\""))print(res.total)# >>> 1 (Result{1 total, docs: [Document {'id': 'bicycle:8'...)
Node.js
import assert from 'node:assert';import fs from 'node:fs';import { createClient, SchemaFieldTypes, AggregateGroupByReducers, AggregateSteps} from 'redis';const client = createClient();await client.connect().catch(console.error);// create indexawait client.ft.create('idx:bicycle', {'$.description': {type: SchemaFieldTypes.TEXT,AS: 'description'},'$.price': {type: SchemaFieldTypes.NUMERIC,AS: 'price'},'$.condition': {type: SchemaFieldTypes.TAG,AS: 'condition'}}, {ON: 'JSON',PREFIX: 'bicycle:'})// load dataconst bicycles = JSON.parse(fs.readFileSync('data/query_em.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:[270 270]');console.log(res1.total); // >>> 1try {const res2 = await client.ft.search('idx:bicycle', '@price:[270]');console.log(res2.total); // >>> 1assert.strictEqual(res2.total, 1);} catch (err) {console.log("'@price:[270]' syntax not yet supported.");}try {const res3 = await client.ft.search('idx:bicycle', '@price==270');console.log(res3.total); // >>> 1assert.strictEqual(res3.total, 1);} catch (err) {console.log("'@price==270' syntax not yet supported.");}// FILTER is not supported// const res4 = await client.ft.search('idx:bicycle', '*', {// FILTER: {// field: 'price',// min: 270,// max: 270,// }// });// console.log(res4.total); // >>> 1const res5 = await client.ft.search('idx:bicycle', '@condition:{new}');console.log(res5.total); // >>> 5await client.ft.create('idx:email', {'$.email': {type: SchemaFieldTypes.TAG,AS: 'email'}}, {ON: 'JSON',PREFIX: 'key:'})await client.json.set('key:1', '$', { email: 'test@redis.com' });try {const res6 = await client.ft.search('idx:email', 'test@redis.com', { DIALECT: 2 });console.log(res6);} catch (err) {console.log("'test@redis.com' syntax not yet supported.");}const res7 = await client.ft.search('idx:bicycle', '@description:"rough terrain"');console.log(res7.total); // >>> 1 (Result{1 total, docs: [Document {'id': 'bicycle:8'...)
