3

假设我正在编写一个日志分析应用程序。主域对象将是一个 LogEntry。此外。应用程序的用户定义了一个 LogTopic,它描述了他们感兴趣的日志条目。当应用程序接收到日志条目时,它会将它们添加到 couchDB,并根据系统中的所有 LogTopics 检查它们是否符合主题中的条件. 如果是,则系统应记录该条目与主题匹配。因此,LogEntries 和 LogTopics 之间存在多对多的关系。

如果我将其存储在 RDBMS 中,我会执行以下操作:

CREATE TABLE Entry (
 id int,
 ...
)

CREATE TABLE Topic (
 id int,
 ...
)

CREATE TABLE TopicEntryMap (
 entry_id int,
 topic_id int
)

使用 CouchDB,我首先尝试只有两种文档类型。我有一个 LogEntry 类型,看起来像这样:

{
  'type': 'LogEntry',
  'severity': 'DEBUG',
  ...
}

我会有一个 LogTopic 类型,看起来像这样:

{
  'type': 'LogTopic',
  'matching_entries': ['log_entry_1','log_entry_12','log_entry_34',....],
  ...
}

您可以看到我通过matching_entries在每个 LogTopic 文档中使用一个字段来存储 LogEntry 文档 ID 列表来表示关系。这在一定程度上可以正常工作,但是当多个客户端都尝试将匹配条目添加到主题时,我遇到了问题。两者都尝试乐观更新,一个失败了。我现在使用的解决方案是从本质上重现 RDBMS 方法,并添加第三种文档类型,例如:

{
  'type':'LogTopicToLogEntryMap',
  'topic_id':'topic_12',
  'entry_id':'entry_15'
}

这有效,并且克服了并发更新问题,但我有两个保留意见:

  1. 我担心我只是在使用这种方法,因为这是我在关系数据库中所做的。我想知道是否有更类似于 couchDB(放松?)的解决方案。
  2. 我的视图无法再一次调用中检索特定主题的所有条目。我以前的解决方案允许这样做(如果我使用了 include_docs 参数)。

有人对我有更好的解决方案吗?如果我也发布我正在使用的视图会有帮助吗?

4

3 回答 3

11

我将这个问题交叉发布到couchdb 用户邮件列表,Nathan Stott向我指出了 Christopher Lenz的一篇非常有用的博客文章

于 2009-12-01T03:25:00.453 回答
4

你的方法很好。使用 CouchDB 并不意味着您将放弃关系建模。您将需要运行两个查询,但那是因为这是一个“连接”。带有连接的 SQL 查询也很慢,但 SQL 语法允许您在一条语句中表达查询。

在我使用 CouchDB 的几个月经验中,我发现:

  1. 无模式,因此设计应用程序模型既快速又灵活
  2. CRUD 就在那里,因此开发您的应用程序既快速又灵活
  3. 再见 SQL 注入
  4. 什么是 SQL 连接需要在 CouchDB 中做更多的工作

根据您的需要,我发现 couchdb-lucene 对于构建更复杂的查询也很有用。

于 2009-12-01T01:21:49.077 回答
0

我会尝试设置关系,以便 LogEntrys 知道它们属于哪个 LogTopics。这样,插入 LogEntry 不会产生冲突,因为不需要更改 LogTopics。

然后,一个简单的 map 函数会为其所属的每个 LogTopic 发出一次 LogEntry,本质上是动态构建您的 TopicEntryMap:

"map": function (doc) {
    doc.topics.map(function (topic) {
        emit(topic, doc);
    });
}

这样,使用?key=<topic>参数查询视图将为您提供属于某个主题的所有条目。

于 2010-08-13T12:25:23.200 回答