以下摘录自电子书。 点击此处下载完整电子书。
当有人想在应用程序中使用 NoSQL 时,最常出现的问题是“我如何构建我的数据?” 这个问题的简短答案是,正如你可能猜到的那样,这取决于情况。有几个问题可以帮助你确定如何在 NoSQL 数据库中构建数据。你的应用程序是读密集型还是写密集型?你的应用程序的用户体验是什么样的?你的数据需要如何呈现给用户?你将存储多少数据?你需要考虑哪些性能因素?你预计如何扩展你的应用程序?
这些问题只是你在开始使用 NoSQL 时需要问自己的问题的一小部分。关于 NoSQL 数据库的一个常见误解是,由于它们是“无模式的”,所以你不必担心你的模式。实际上,无论你选择什么数据库,你的模式都非常重要。你还需要确保你选择的模式可以很好地扩展到你计划使用的数据库。
在本电子书中,你将学习如何在 NoSQL 中进行数据建模,特别是在 Redis 的上下文中。Redis 是一个非常棒的数据库,它可以用来展示几种 NoSQL 模式和实践。Redis 不仅被开发人员广泛使用和喜爱,而且它也是一个多模型数据库。这意味着,虽然本电子书中涵盖的大多数模式都适用于不同类型的数据库(例如文档、图、时间序列等),但使用 Redis,你可以在单个数据库中应用所有模式。
在学习完本电子书后,你应该具备:
我相信你在一定程度上了解 SQL 和 NoSQL 之间的区别。SQL 是一种结构化查询语言,而 NoSQL 根据上下文可以指代许多不同的东西。但是,一般来说,在 NoSQL 中进行数据建模的方法与在 SQL 中根本不同。在可扩展性方面也存在差异,NoSQL 更易于水平扩展。
在构建应用程序时,你可能正在使用面向对象的语言,如 JavaScript、Java、C# 等。你的数据以字符串、列表、集合、哈希、JSON 等形式表示。但是,如果你将数据存储在 SQL 数据库或文档数据库中,你需要将数据压缩并转换为多个表或集合。你还需要复杂的查询(例如 SQL 查询)才能提取数据。这被称为 **阻抗不匹配**,这是 NoSQL 存在的根本原因。
大型应用程序可能会使用其他系统来存储数据,例如 Neo4J 用于图数据,MongoDB 用于文档数据,InfluxDB 用于时间序列数据等等。使用独立的数据库将阻抗不匹配问题转变为数据库编排问题。你必须处理连接到不同数据库的多个连接,以及学习不同的客户端库。
使用 Redis,除了字符串、列表、集合和哈希等基本数据结构之外,你还可以存储高级数据结构,例如 JSON 用于文档,Search 用于辅助索引,Time Series 用于时间序列数据,以及 Probabilistic 数据(想想排行榜)。
这减少了阻抗不匹配,因为你的数据存储在 15 种结构中的一种,几乎没有转换。你还可以使用单个连接(或连接池)和客户端库来访问你的数据。最终得到的是一个简化的架构,具有专用的模型,速度极快且易于管理。出于这个原因,本电子书将使用 Redis 来解释几种 NoSQL 数据建模模式。
大多数开发人员至少对 SQL 和如何在 SQL 中进行数据建模有一点了解。这是因为 SQL 被广泛使用,并且有许多关于 SQL 的优秀书籍,甚至还有完整的课程。NoSQL 正在快速发展并变得越来越流行。但是,考虑到 NoSQL 不仅仅是一个文档存储,因此有许多领域需要涵盖。这就是为什么在本电子书中,当介绍某些 NoSQL 数据建模模式时,还会介绍在 SQL 中进行数据建模可能是什么样的。
在 SQL 中进行数据建模时,通常会关注关系,因为 SQL 旨在对关系数据进行基于集合的操作。NoSQL 没有这个限制,在进行数据建模方面更灵活。但是,这可能会导致过于复杂的模式。在考虑 NoSQL 模式设计时,始终要考虑性能,并尽量保持简单。
所以,让我们从一个 SQL 开发人员非常熟悉的概念开始: **关系**。
假设你正在创建一个销售电子产品的零售应用程序。让我们使用 **图片 1** 和 **图片 2** 作为标准零售电子商务应用程序 UI 的示例。首先,你将创建一个所有电子产品的列表视图,然后创建一个详细视图,显示每个项目的详细信息。列表视图中的每个项目与项目的详细视图(显示在 **图片 2** 中)之间存在 1 对 1 关系。详细视图显示所有详细信息,例如多张照片、描述、制造商、尺寸、重量等等。
在关系数据库中,你可能创建一个名为 **products** 的表,其中每一行只包含足以在列表视图中显示信息的数据。然后,你可能创建一个名为 **product_details** 的表,其中每一行包含其他详细信息。你还需要一个 **product_images** 表,用来存储产品的图片。你可以在 **图片 3** 中看到实体关系图。
图片 3
图片 3 描绘了 **products**、**product_details** 和 **product_images** 之间的实体关系,并代表了一个规范化的数据模型,其中在 **products** 表中有一个反规范化的字段 **image**。这样做的原因是为了避免在选择产品以用于列表视图时必须使用 SQL JOIN。使用这个模型,用于获取列表视图所需数据的 SQL 查询可能类似于 **代码示例 1**。
SELECT
p.id, p.name, p.image, p.price, pi.url
FROM
products p
在 Redis 中,与关系数据库类似,你可以创建一个名为 **products** 的集合,另一个名为 **product_details** 的集合。但是,使用 Redis JSON,你可以通过简单地将 **product_images** 和 **product_details** 直接嵌入到 **Products** 集合中来改进这一点。然后,当你查询 **Products** 集合时,根据你要创建的视图来指定你需要哪些字段。
这将使你能够轻松地将所有数据保存在一个地方。这被称为 **嵌入模式**,是你在 Redis JSON 等 NoSQL 文档数据库中最常见的模式之一。**代码示例 2** 使用 Python 和一个名为 Redis OM 的客户端库(Redis 的 ORM)来对 **Products** 和 **ProductDetails** 进行建模。请注意,**ProductDetails** 被直接嵌入到 **Products** 中,因此产品的全部数据都将存储在同一文档中。
class ProductDetail(EmbeddedJsonModel):
description: str
manufacturer: str
dimensions: str
weight: str
images: List[str]
class Product(JsonModel):
name: str = Field(index=True)
image: str = Field(index=True)
price: int = Field(index=True)
details: Optional[ProductDetail]
代码示例 2 也展示了如何使用 Redis OM 和 Redis Search 对字段进行索引。这样做不仅将 Redis 变成一个文档存储,也变成一个搜索引擎,因为 Redis Search 支持二级索引和搜索。当您使用 Redis OM 创建模型时,它会自动管理 Redis Search 中的二级索引。
使用 Redis OM,我们可以编写一个函数来检索我们的 products 列表,用于列表视图,如 代码示例 3 所示。
async def get_product_list():
results = await connections \
.get_redis_connection() \
.execute_command(
f'FT.SEARCH {Product.Meta.index_name} * LIMIT 0 10 RETURN 3 name image price'
)
return Product.from_redis(results)
请注意,在 代码示例 3 中,我们使用的是 FT.SEARCH 命令,该命令指定了由 Redis OM 管理的索引,并返回三个字段:name、image 和 price。虽然所有文档都包含 details 和 images,但我们不想在列表视图中显示它们,因此不需要查询它们。当我们想要详细视图时,可以查询整个 Product 文档。有关如何查询整个文档,请参见 代码示例 4 。
async def get_product_details(product_id: str):
return await Product.get(product_id)
使用 Redis 时,可以使用 RedisInsight 作为 GUI 工具来可视化和交互数据库中的数据。 图片 4 展示了 Products 文档的外观。
图片 4
我相信您渴望了解更多,所以请 点击此处下载完整的电子书。