Appearance
Redis 作为文档数据库快速入门指南
了解如何将 Redis 用作文档数据库
本快速入门指南向您展示如何:
- 创建二级索引
- 添加 JSON 文档
- 搜索和查询您的数据
本文中的示例引用了一个简单的 bicycle 清单,其中包含具有以下结构的 JSON 文档:
json
{
"brand": "brand name",
"condition": "new | used | refurbished",
"description": "description",
"model": "model",
"price": 0
}
设置
开始使用 Redis Stack 的最简单方法是使用 Redis Cloud:
- 创建一个免费帐户。
- 按照说明创建免费数据库。
这个免费的 Redis Cloud 数据库开箱即用,具有所有 Redis Stack 功能。
您也可以使用安装指南在本地计算机上安装 Redis Stack。
连接
第一步是连接到您的 Redis Stack 数据库。您可以在此文档站点的 connection 部分找到有关连接选项的更多详细信息。以下示例显示了如何连接到在 localhost (-h 127.0.0.1) 上运行并侦听默认端口 (-p 6379) 的 Redis Stack 服务器:
bash
redis-cli -h 127.0.0.1 -p 6379
python
r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)
js
const client = createClient();
client.on('error', err => console.log('Redis Client Error', err));
await client.connect();
java
// UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");
JedisPooled jedis = new JedisPooled("localhost", 6379);
csharp
var redis = ConnectionMultiplexer.Connect("localhost:6379");
var db = redis.GetDatabase();
var ft = db.FT();
var json = db.JSON();
提示
您可以从 Redis Cloud 数据库配置页面复制并粘贴连接详细信息。以下是托管在 AWS 区域us-east-1
中并侦听端口 16379 的云数据库的示例连接字符串:redis-16379.c283.us-east-1-4.ec2.cloud.redislabs.com:16379
。连接字符串的格式为host:port
.您还必须复制并粘贴云数据库的用户名和密码,然后将凭证传递给您的客户端或在建立连接后使用 AUTH 命令。
创建索引
如内存数据存储快速入门指南中所述,Redis 允许您通过键直接访问项目。您还学习了如何扫描key空间。您可以使用其他数据结构(例如,哈希和排序集)作为二级索引,而您的应用程序需要手动维护这些索引。Redis Stack 允许您声明哪些字段是自动索引的,从而将 Redis 转变为文档数据库。Redis Stack 目前支持在哈希和 JSON 文档上创建二级索引。
以下示例显示了一个 FT.CREATE
命令,该命令创建包含一些文本字段、数值字段 (price) 和标签字段 (condition) 的索引。文本字段的权重为 1.0,这意味着它们在全文搜索的上下文中具有相同的相关性。字段名称遵循 JSONPath 概念。每个此类索引字段都映射到 JSON 文档中的一个属性。
bash
> FT.CREATE idx:bicycle ON JSON PREFIX 1 bicycle: SCORE 1.0 SCHEMA $.brand AS brand TEXT WEIGHT 1.0 $.model AS model TEXT WEIGHT 1.0 $.description AS description TEXT WEIGHT 1.0 $.price AS price NUMERIC $.condition AS condition TAG SEPARATOR ,
OK
python
schema = (
TextField("$.brand", as_name="brand"),
TextField("$.model", as_name="model"),
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),
)
js
const schema = {
'$.brand': {
type: SchemaFieldTypes.TEXT,
SORTABLE: true,
AS: 'brand'
},
'$.model': {
type: SchemaFieldTypes.TEXT,
AS: 'model'
},
'$.description': {
type: SchemaFieldTypes.TEXT,
AS: 'description'
},
'$.price': {
type: SchemaFieldTypes.NUMERIC,
AS: 'price'
},
'$.condition': {
type: SchemaFieldTypes.TAG,
AS: 'condition'
}
};
try {
await client.ft.create('idx:bicycle', schema, {
ON: 'JSON',
PREFIX: 'bicycle:'
});
} catch (e) {
if (e.message === 'Index already exists') {
console.log('Index exists already, skipped creation.');
} else {
// Something went wrong, perhaps RediSearch isn't installed...
console.error(e);
process.exit(1);
}
}
java
SchemaField[] schema = {
TextField.of("$.brand").as("brand"),
TextField.of("$.model").as("model"),
TextField.of("$.description").as("description"),
NumericField.of("$.price").as("price"),
TagField.of("$.condition").as("condition")
};
jedis.ftCreate("idx:bicycle",
FTCreateParams.createParams()
.on(IndexDataType.JSON)
.addPrefix("bicycle:"),
schema
);
csharp
var schema = new Schema()
.AddTextField(new FieldName("$.Brand", "Brand"))
.AddTextField(new FieldName("$.Model", "Model"))
.AddTextField(new FieldName("$.Description", "Description"))
.AddNumericField(new FieldName("$.Price", "Price"))
.AddTagField(new FieldName("$.Condition", "Condition"));
ft.Create(
"idx:bicycle",
new FTCreateParams().On(IndexDataType.JSON).Prefix("bicycle:"),
schema);
任何预先存在的带有键前缀bicycle:
的 JSON 文档都会自动添加到索引中。此外,在创建索引后创建或修改的具有该前缀的任何 JSON 文档都将添加或重新添加到索引中。
添加 JSON 文档
以下示例显示了如何使用 JSON.SET
命令创建新的 JSON 文档:
bash
> JSON.SET "bicycle:0" "." "{\"brand\": \"Velorim\", \"model\": \"Jigger\", \"price\": 270, \"description\": \"Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids\\u2019 pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.\", \"condition\": \"new\"}"
OK
python
for bid, bicycle in enumerate(bicycles):
r.json().set(f"bicycle:{bid}", Path.root_path(), bicycle)
js
await Promise.all(
bicycles.map((bicycle, i) => client.json.set(`bicycle:${i}`, '$', bicycle))
);
java
Query query1 = new Query("*");
List<Document> result1 = jedis.ftSearch("idx:bicycle", query1).getDocuments();
System.out.println("Documents found:" + result1.size());
// Prints: Documents found: 10
csharp
for (int i = 0; i < bicycles.Length; i++)
{
json.Set($"bicycle:{i}", "$", bicycles[i]);
}
使用 Redis 查询引擎进行搜索和查询
通配符查询
您可以使用 FT.SEARCH
命令。请注意下面的LIMIT
子句,它允许结果分页。
bash
> FT.SEARCH "idx:bicycle" "*" LIMIT 0 10
1) (integer) 10
2) "bicycle:1"
3) 1) "$"
2) "{\"brand\":\"Bicyk\",\"model\":\"Hillcraft\",\"price\":1200,\"description\":\"Kids want to ride with as little weight as possible. Especially on an incline! They may be at the age when a 27.5\\\" wheel bike is just too clumsy coming off a 24\\\" bike. The Hillcraft 26 is just the solution they need!\",\"condition\":\"used\"}"
4) "bicycle:2"
5) 1) "$"
2) "{\"brand\":\"Nord\",\"model\":\"Chook air 5\",\"price\":815,\"description\":\"The Chook Air 5 gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. The lower top tube makes it easy to mount and dismount in any situation, giving your kids greater safety on the trails.\",\"condition\":\"used\"}"
6) "bicycle:4"
7) 1) "$"
python
res = index.search(Query("*"))
print("Documents found:", res.total)
# >>> Documents found: 10
js
let result = await client.ft.search('idx:bicycle', '*', {
LIMIT: {
from: 0,
size: 10
}
});
console.log(JSON.stringify(result, null, 2));
/*
{
"total": 10,
"documents": ...
}
*/
java
Query query1 = new Query("*");
List<Document> result1 = jedis.ftSearch("idx:bicycle", query1).getDocuments();
System.out.println("Documents found:" + result1.size());
// Prints: Documents found: 10
csharp
var query1 = new Query("*");
var res1 = ft.Search("idx:bicycle", query1).Documents;
Console.WriteLine(string.Join("\n", res1.Count()));
// Prints: Documents found: 10
单字词全文查询
以下命令显示了一个简单的单项查询,用于查找具有特定型号的所有自行车:
bash
> FT.SEARCH "idx:bicycle" "@model:Jigger" LIMIT 0 10
1) (integer) 1
2) "bicycle:0"
3) 1) "$"
2) "{\"brand\":\"Velorim\",\"model\":\"Jigger\",\"price\":270,\"description\":\"Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids\xe2\x80\x99 pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.\",\"condition\":\"new\"}"
python
res = index.search(Query("@model:Jigger"))
print(res)
# >>> Result{1 total, docs: [
# Document {
# 'id': 'bicycle:0',
# 'payload': None,
# 'json': '{
# "brand":"Velorim",
# "model":"Jigger",
# "price":270,
# ...
# "condition":"new"
# }'
# }]}
js
result = await client.ft.search(
'idx:bicycle',
'@model:Jigger',
{
LIMIT: {
from: 0,
size: 10
}
});
console.log(JSON.stringify(result, null, 2));
/*
{
"total": 1,
"documents": [{
"id": "bicycle:0",
"value": {
"brand": "Velorim",
"model": "Jigger",
"price": 270,
"description": "Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.",
"condition": "new"
}
}]
}
*/
java
Query query2 = new Query("@model:Jigger");
List<Document> result2 = jedis.ftSearch("idx:bicycle", query2).getDocuments();
System.out.println(result2);
// Prints: [id:bicycle:0, score: 1.0, payload:null,
// properties:[$={"brand":"Velorim","model":"Jigger","price":270,"description":"Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.","condition":"new"}]]
csharp
var query2 = new Query("@Model:Jigger");
var res2 = ft.Search("idx:bicycle", query2).Documents;
Console.WriteLine(string.Join("\n", res2.Select(x => x["json"])));
// Prints: {"Brand":"Moore PLC","Model":"Award Race","Price":3790.76,
// "Description":"This olive folding bike features a carbon frame
// and 27.5 inch wheels. This folding bike is perfect for compact
// storage and transportation.","Condition":"new"}
完全匹配查询
下面是一个命令,用于执行完全匹配查询,该查询查找品牌名称为Noka Bikes
的所有自行车 。在文本字段上构建完全匹配查询时,必须在搜索词两边使用双引号。
bash
> FT.SEARCH "idx:bicycle" "@brand:\"Noka Bikes\"" LIMIT 0 10
1) (integer) 1
2) "bicycle:4"
3) 1) "$"
2) "{\"brand\":\"Noka Bikes\",\"model\":\"Kahuna\",\"price\":3200,\"description\":\"Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women\xe2\x80\x99s saddle, different bars and unique colourway.\",\"condition\":\"used\"}"
python
res = index.search(Query('@brand:"Noka Bikes"'))
print(res)
# >>> Result{1 total, docs: [
# Document {
# 'id': 'bicycle:4',
# 'payload': None,
# 'json': '{
# "brand":"Noka Bikes",
# "model":"Kahuna",
# "price":3200,
# ...
# "condition":"used"
# }'
# }]}
js
result = await client.ft.search(
'idx:bicycle',
'@brand:"Noka Bikes"',
{
LIMIT: {
from: 0,
size: 10
}
}
);
console.log(JSON.stringify(result, null, 2));
/*
{
"total": 1,
"documents": [{
"id": "bicycle:4",
"value": {
"brand": "Noka Bikes",
"model": "Kahuna",
"price": 3200,
"description": "Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women’s saddle, different bars and unique colourway.",
"condition": "used"
}
}]
}
*/
java
Query query5 = new Query("@brand:\"Noka Bikes\"");
List<Document> result5 = jedis.ftSearch("idx:bicycle", query5).getDocuments();
System.out.println(result5);
// Prints: [id:bicycle:4, score: 1.0, payload:null,
// properties:[$={"brand":"Noka Bikes","model":"Kahuna","price":3200,"description":"Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women’s saddle, different bars and unique colourway.","condition":"used"}]]
csharp
var query4 = new Query("@Brand:\"Noka Bikes\"");
var res4 = ft.Search("idx:bicycle", query4).Documents;
Console.WriteLine(string.Join("\n", res4.Select(x => x["json"])));
// Prints: {"Brand":"Moore PLC","Model":"Award Race","Price":3790.76,
// "Description":"This olive folding bike features a carbon frame
// and 27.5 inch wheels. This folding bike is perfect for compact
// storage and transportation.","Condition":"new"}
请参阅 查询文档 以了解如何进行更高级的查询
后续步骤
您可以在以下快速入门指南中了解有关如何将 Redis Stack 用作矢量数据库的更多信息:
- Redis 作为矢量数据库