20

我正在考虑为各种类型的数据创建一个开源数据管理 Web 应用程序。

特权用户必须能够

  • 添加新的实体类型(例如“用户”或“家庭”)
  • 向实体类型添加新属性(例如“性别”到“用户”)
  • 删除/修改实体和属性

这些将是特权用户的常见任务。他将通过应用程序的 Web 界面执行此操作。最后,所有数据都必须可供应用程序的所有类型的用户搜索和排序。有两个问题困扰我:

a) 数据应该如何存储在数据库中?我应该在运行时动态添加/删除数据库表和/或列吗?

我不是数据库专家。我一直在想,就关系数据库而言,应用程序必须能够在运行时动态添加/删除表(实体)和/或列(属性)。我不喜欢这个主意。同样,我正在考虑是否应该在 NoSQL 数据库中处理此类动态数据。

无论如何,我相信这类问题有一个智能的规范解决方案,这是我迄今为止没有找到和想到的。这种动态数据管理的最佳方法是什么?

b) 如何使用 ORM 或 NoSQL 在 Python 中实现这一点?

如果您推荐使用关系数据库模型,那么我想使用 SQLAlchemy。但是,我看不到如何在运行时使用 ORM 动态创建表/列。这就是为什么我希望有一种比在运行时创建表和列更好的方法的原因之一。推荐的数据库模型是否可以使用 SQLAlchemy 有效实现?

如果您推荐使用 NoSQL 数据库,是哪一个?我喜欢使用 Redis——你能想象一个基于 Redis 的高效实现吗?

感谢您的建议!

编辑以回应一些评论:

这个想法是某个实体(“表”)的所有实例(“行”)共享同一组属性/属性(“列”)。但是,如果某些实例的某些属性/属性具有空值,则它将是完全有效的。

基本上,用户将通过网站上的简单表格搜索数据。例如,它们查询具有属性 P 的实体 E 的所有实例,该属性 P 的值 V 高于 T。结果可以按任何属性的值排序。

数据集不会变得太大。因此,我认为即使是最愚蠢的方法仍然会导致工作系统。但是,我是一名爱好者,我想应用现代和适当的技术,同时我想了解理论瓶颈。我想使用这个项目来收集设计“Pythonic”、最先进、可扩展且可靠的 Web 应用程序的经验。

我看到第一条评论倾向于推荐 NoSQL 方法。虽然我真的很喜欢 Redis,但不利用 Mongo/Couch 的 Document/Collection 模型似乎很愚蠢。我一直在研究 Python 的 mongodb 和 mongoengine。通过这样做,我是否朝着正确的方向迈出了一步?

编辑 2 以回应一些答案/评论:

从您的大多数答案中,我得出结论,在关系图中动态创建/删除表和列不是要走的路。这已经是有价值的信息。此外,一种观点是,动态修改实体和属性的整个想法可能是糟糕的设计。

由于这种动态特性应该是应用程序的主要目的/功能,我不会放弃这一点。从理论的角度来看,我接受在动态数据模型上执行操作必然比在静态数据模型上执行操作慢。这完全没问题。

用抽象的方式表达,应用程序需要管理

  1. 数据布局,即有效实体类型的“动态列表”和每个有效实体类型的属性“动态列表”
  2. 数据本身

我正在寻找一种智能且有效的方法来实现这一点。从您的回答看来,NoSQL 似乎是这里的出路,这是另一个重要的结论。

4

4 回答 4

20

SQL 或 NoSQL 的选择不是您的问题。一般来说,您需要阅读更多关于数据库设计的内容。正如你所说,你不是数据库专家(你也不需要是),但你绝对必须多学习一点 RDBMS 范式。

业余爱好者选择 NoSQL 解决方案是一个常见的错误。有时 NoSQL 是一个很好的解决方案,但大多数时候不是。

以您提到的 MongoDB 为例(它是我尝试过的优秀 NoSQL 解决方案之一)。无模式,对吧?错误..不完全是。你会看到什么时候没有模式意味着没有约束、验证等。但是你的应用程序的模型/实体不能凭空存在!当然,您在软件层上实现一些约束和验证逻辑。所以我给你mongokit!我将仅从项目的描述中引用这一点

MongoKit 在出色的 pymongo 驱动程序之上带来结构化模式和验证层

嗯……非结构化变成了结构化。

至少我们没有 SQL 对吧?是的,我们没有。我们有一种不同的查询语言,它当然不如 SQL。至少您不需要使用 map/reduce 来进行基本查询(请参阅 CouchDB)。

不要误会我的意思,NoSQL(尤其是 MongoDB)有它的用途,但大多数时候这些技术被用于错误的原因。

此外,如果您关心严重的持久性和数据完整性,请忘记 NoSQL 解决方案。所有这些技术都太实验性了,无法保存您的严肃数据。通过研究一下谁(除了谷歌/亚马逊)使用 NoSQL 解决方案以及究竟是为了什么,你会发现几乎没有人使用它来保存他们的重要数据。他们主要将它们用于日志记录、消息和实时数据。基本上可以从他们的 SQL 数据库存储中减轻一些负担。

在我看来,Redis 可能是唯一能够在 NoSQL 爆炸中毫发无损的项目。也许是因为它并没有宣传自己是 NoSQL,而是作为键值存储,这正是它的本质,而且非常好!他们似乎对坚持很认真。这是一把瑞士军刀,但不是完全替换您的 RDBMS 的好解决方案。

对不起,我说的太多了:)

所以这是我的建议:

1)研究一下RDBMS模型。

2) 如果您的大部分项目都将使用 RDBMS,那么 Django 是一个很好的框架。

3) Postgresql 摇滚!还要记住,9.2 版将带来原生JSON支持。您可以在其中转储所有“动态”属性,并且可以使用辅助存储/引擎对所述属性执行查询(map/reduce)。有你的蛋糕,也吃吧!

4)对于严肃的搜索功能,请考虑专门的引擎,如solr

编辑:2013 年 4 月 6 日

5) django-ext-hstore让您可以访问 postgresql hstore 类型。它类似于 python 字典,您可以对其执行查询,但限制是您不能将嵌套字典作为值。key 的值也只能是 type string

玩得开心


更新以响应 OP 的评论

0) 考虑应用程序“包含数据”并且已经使用了一段时间

我不确定您的意思是它包含旧版 dbms 中的数据,还是您只是想说“想象数据库不为空并考虑以下几点……”。在前一种情况下,这似乎是一个迁移问题(完全不同的问题),在后一种情况下,好吧。

1) 管理员删除实体“family”和所有相关数据

为什么有人要完全消除一个实体(表)?您的申请要么与家庭、房屋等有关,要么与此无关。当然,删除族的实例(行)是可以理解的。

2)管理员创建实体“房子”

与#1 相同。如果您在您的应用程序中引入一个全新的实体,那么它很可能会封装语义和业务逻辑,必须为其编写新代码。随着时间的推移,所有应用程序都会发生这种情况,当然需要创建一个新表,或者可能是ALTER现有的表。但此过程不是您的应用程序功能的一部分。即它很少发生,并且是迁移/重构问题。

3)管理员添加属性“楼层”,“年龄”,..

为什么?难道我们事先不知道 aHouse有楼层吗?那aUser有性别吗?动态添加和删除这种类型的属性不是一个特性,而是一个设计缺陷。它是分析/设计阶段的一部分,用于识别您的实体及其各自的属性。

4)特权用户添加一些房屋。

是的,他正在向现有实体(表)添加一个实例(行)House

5) 用户搜索所有至少五层楼价低于 100 美元的房子

可以使用 SQL 或 NoSQL 解决方案实现的完全有效的查询。在 django 中,它会是这样的:

House.objects.filter(floors__gte=5, price__lt=100)

前提是House具有属性floorsprice。但是,如果您需要进行基于文本的查询,那么 SQL 和 NoSQL 都不会令人满意。因为您不想自己实现分词干提取!您将使用一些已经讨论过的解决方案(Solr、ElasticSearch 等)。

一些更一般的注释:

您给出的示例Houses及其Users属性不保证任何动态模式。也许您简化了您的示例只是为了说明您的观点,但是您谈论添加/删除Entities(tables)就像它们是数据库中的行一样。实体应该在应用程序中很重要。它们定义了应用程序的目的及其功能。因此,它们不可能每分钟都改变。

你还说:

The idea is that all instances ("rows") of a certain entity ("table") share the same set of properties/attributes ("columns"). However, it will be perfectly valid if certain instances have an empty value for certain properties/attributes.

这似乎是属性具有null=True.

最后一点,我想建议你尝试两种方法(SQL 和 NoSQL),因为你的职业似乎并不依赖于这个项目。这将是一次受益的经历,因为您将亲身了解每种方法的优缺点。甚至如何将这些方法“混合”在一起。

于 2012-05-23T01:18:49.370 回答
6

您要问的是许多系统中的一个常见要求——如何扩展核心数据模型来处理用户定义的数据。这是打包软件(通常以一种方式处理)和开源软件(以另一种方式处理)的流行要求。

早期关于 RDBMS 设计的更多信息的建议通常不会受到伤害。我要补充的是,不要陷入在您自己的特定于应用程序的数据模型中重新实现关系数据库的陷阱!我已经多次看到这样做了,通常是在打包的软件中。不想将核心数据模型(或更改它的权限)暴露给最终用户,开发人员创建了一个通用数据结构和一个应用程序接口,允许最终用户定义实体、字段等,但不使用 RDBMS 工具。这通常是一个错误,因为很难像经验丰富的 RDBMS 为您做的那样彻底或没有错误,而且可能需要很多时间。这很诱人,但恕我直言,这不是一个好主意。

假设数据模型更改是全局性的(一旦管理员进行更改,所有用户共享),我解决此问题的方法是创建一个应用程序界面,位于管理员用户和 RDBMS 之间,并应用您需要的任何规则应用于数据模型更改,然后将最终更改传递给 RDBMS。因此,例如,您可能有规则说实体名称需要遵循某种格式,允许新实体具有现有表的外键但必须始终使用 DELETE CASCADE 规则,字段只能是某些数据类型,所有字段必须有默认值等。您可以有一个非常简单的屏幕,要求用户提供实体名称、字段名称和默认值等,然后生成 SQL 代码(包括所有规则)以对数据库进行这些更改。

一些常见的规则以及您将如何解决它们将是这样的:

-- 如果一个字段不为空并且有默认值,并且在管理员添加该字段之前表中已经存在记录,则在创建字段时更新现有记录以具有默认值(多步骤--添加允许为空的字段;更新所有现有记录;更改表以强制使用默认值不为空)- 否则您将无法使用字段级完整性规则)

-- 新表必须具有不同的命名模式,以便您可以继续将核心数据模型与用户扩展数据模型区分开来,即核心和用户定义具有不同的 RDBMS 所有者(dbo. vs. user.)或前缀(无对于核心,__ 用于用户定义)或类似的东西。

-- 可以将字段添加到核心数据模型中的表(只要它们容忍空值或具有默认值),并且管理员可以删除管理员添加到核心数据模型表中的字段,但管理员无法删除定义为核心数据模型一部分的字段。

换句话说 - 使用 RDBMS 的强大功能来定义表和管理数据,但为了确保始终应用您需要的任何约定或规则,请通过构建应用程序到数据库管理功能来做到这一点,而不是给予管理员用户直接数据库访问权限。

如果您真的只想通过 DB 层执行此操作,您可能可以通过创建一堆实现相同逻辑的存储过程和触发器来实现相同的目标(谁知道呢,也许您会为您的应用程序这样做)。这可能更多的是一个问题,即您的管理员用户在数据库层中工作与通过中间应用程序工作的舒适程度。


所以直接回答你的问题:

(1) 是的,在运行时添加表和列,但请考虑您需要具备的规则,以确保即使添加了用户定义的数据后您的应用程序也能正常工作,并选择一种方式来执行这些规则(通过应用程序或当您处理表和字段更改时,通过数据库/存储过程或其他方式。

(2) 此问题不受您选择 SQL 与 NoSQL 引擎的强烈影响。在每种情况下,您都有一个核心数据模型和一个扩展数据模型。如果您可以设计您的应用程序以响应动态数据模型(例如,在将字段添加到数据库表或其他任何内容时将新字段添加到屏幕),那么您的应用程序将很好地响应核心数据模型和用户定义数据模型的变化。这是一个有趣的挑战,但受数据库实现风格选择的影响不大。

祝你好运!

于 2012-05-29T04:08:21.510 回答
4

模型对象(RDBMS、NoSQL 等)的持久性引擎可能并不重要。您正在寻找的技术是用于搜索和查找对象的索引。

我认为您需要使用他们的模式找到您的对象。因此,如果模式是动态定义的并持久保存在数据库中,您可以构建动态搜索表单等。需要某种实体和属性对真实对象的引用。

看一下实体-属性-模型模式(EAV)。这可以通过 SQLAlchemy 实现,以使用 RDBMS 数据库作为垂直存储模式和数据并将它们关联起来的手段。

您正在进入语义 Web 编程领域,也许您应该少读本书的第一章:

语义网编程

它讲述了您的问题的全部故事:从刚性模式到动态模式,首先实现为键值存储,后来改进为关系模型上的图形持久性。

我的观点是,现在最好的实现可以通过图形数据库实现,当前实现的一个很好的例子是 Berkeley DB(一些 LDAP 实现使用 Berkeley DB 作为这个索引问题的技术实现。)

一旦进入图形模型,您就可以对图形进行某种“推理”,使数据库看起来具有某种“智能”。书中有一个例子。

于 2012-05-23T23:05:24.603 回答
3

因此,如果您将实体概念化为“文档”,那么整个问题可以很好地映射到 no-sql 解决方案。正如评论的那样,您需要有某种模型层,它位于您的文档存储之上并执行诸如验证之类的任务,并且可能强制(或鼓励)某种模式,因为没有隐含的后端要求实体中的相同的集合(与表平行)共享模式。

允许特权用户更改您的架构概念(而不是仅向单个文档添加字段 - 这很容易支持)将带来一些挑战 - 您必须处理迁移现有数据以自动匹配新架构。

阅读您的编辑,Mongo 支持您正在寻找的搜索/排序类型,并将为您提供所需的“空单元格”(缺少特定键的文档)的支持。

如果我是你(并且我目前正在开发类似但更简单的产品),我会坚持使用 Mongo,并研究像 Flask 这样的轻量级 Web 框架来提供前端。您将独自提供模型,但您不会与框架的隐式建模选择作斗争。

于 2012-05-22T17:56:50.040 回答