在离散数据结构中存储文本中的元数据


14

我正在开发一个应用程序,它将需要存储inlineintext元数据。我的意思是这样:假设我们有一个长文本,并且我们想存储一些与特定单词或文本句子相关的元数据。

存储此信息的最佳方法是什么?

我的第一个想法是在文本中包含某种Markdown语法,然后在检索时将对其进行解析。看起来像这样:

Lorem ipsum dolor sit amet, consectetuer adipiscing elit,
sed diam __nonummy nibh__[@note this sounds really funny latin]
euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.

这会带来两个我想到的问题:

  1. 相对较小的是,如果所说的语法恰好在所说的文本上,它可能会使解析混乱。
  2. 最重要的是,这不会使此元数据文本本身保持独立

我想拥有一个离散的数据结构来保存这些数据,例如一个存储这些元数据的不同的DB表,这样我就可以以离散的方式使用它们:查询,统计信息,排序等等。


编辑:既然回答者删除了他的答案,我认为在这里添加他的建议可能是一件好事,因为这是在第一个概念上扩展的可行建议。海报建议使用类似的语法,但对元数据链接到PRIMARY KEY该的metadata数据库表。

看起来像这样的东西:

Lorem ipsum dolor sit amet, consectetuer adipiscing elit,
sed diam __nonummy nibh__[15432]
euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.

其中15432将是ID含有必要的,可查询信息的表的行的,按照下面的例子。


我的第二个想法是将这种信息存储在数据库表中,如下所示:

TABLE: metadata

ID    TEXT_ID    TYPE    OFFSET_START    OFFSET_END    CONTENT
1     lipsum     note    68              79            this sounds really funny latin

这样,元数据将具有唯一的ID,text_id作为连接到存储文本的表的外键a ,并且它将使用简单的字符偏移范围将数据与文本本身连接起来。

这样做可以使数据数据保持分离,但是我可以立即用这种方法看到的一个问题是,文本基本上是不可编辑的。或者,如果我想要实现元数据的分配后的文字编辑,我就基本都较之前的版本来计算字符添加或去除,并检查是否每个这样的修改之前或之后添加或删除角色的每个关联的元数据。

对我来说,这听起来像是一种毫无意义的方法。

您对我如何解决此问题有任何指示或建议吗?


编辑2:一些XML问题

添加另一种情况,这对于实现数据和元数据的分离非常必要。

  • 假设我想让不同的用户拥有相同文本的不同元数据集,而每个用户实际上都可能显示其他用户元数据。

此时,很难实现降价类型的任何解决方案(或HTML或XML)。在这种情况下,我想到的唯一解决方案是拥有另一个DB Table,该DB Table将包含原始文本的单个用户版本,并通过使用来连接到原始文本表FOREIGN KEY

不知道这是否也很优雅。

  • XML具有分层数据模型:碰巧其中的任何元素另一个元素的边界的都被视为其元素,在我正在寻找的数据模型中,情况通常并非如此;在XML中,必须先关闭所有元素,然后才能关闭标记,以免元素重叠。

例:

<note content="the beginning of the famous placeholder"> Lorem ipsum dolor坐在 <comment content="I like the sound of amet/elit"> 椅子上 </note>管教成才 </comment> <note content="adversative?"> sed diam nonummy<note content="funny latin"> </note> NIBH euismod tincidunt UT laoreet dolore麦格纳aliquam ERAT volutpat。</note>

这里我们有两个不同的问题:

  1. 不同元素重叠:第一个注释在第一个注释内开始,但在第一个注释结束后结束,即它不是其子项。

  2. 相同元素重叠:最后一个音符和黑体音符重叠;但是,由于它们是同一类元素,因此解析器将在第一个闭包处关闭最后打开的元素,并在最后一个闭包处关闭第一个打开的元素,在这种情况下,这不是预期的。


3
听起来有点像您在编写自己的标记语言。您可以使用具有完善的解析系统的HTML,还可以通过操纵生成的解析树来编辑文本。对于数据库存储,您可以使用NoSQL db,例如Oracle的XMLDB或Mark / Logic。
ipaul

这个问题不是概念上的实际问题。我的意思是,我可以使用HTML或Markdown,或与解析器一起构建非常简单的标记语言。问题是我想将它们分开。将内容保持在最低限度,也许只是将基本的富文本信息保留在内容中,但其他所有内容都应分开。
Sunyatasattva

1
@Sunyatasattva添加这种复杂性有什么好处?
克莱门特·赫雷曼

@ClementHerreman哪个增加了复杂性?您是说保持数据和元数据分离的复杂性吗?
Sunyatasattva

文本是否旨在成为可更改或更新的活动文档,并且需要在文本的多个版本上维护其元数据?还是将元数据应用于其上的文本是完全静态且不变的?
凯尔·洛瑞

Answers:


5

我会混合使用您的解决方案,但是我会使用标准的XML :。你会有这样的语法

Lorem ipsum dolor sit amet, consectetuer adipiscing elit,
sed diam <note content="It sound really funny in latin">nonummy nibh</note>
euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.

为什么选择XML

如果您考虑一下,这就是整个网络的结构:通过html标记传递语义(即您所说的元数据)的内容(实际文本)。

这样,您便拥有了一个非常酷的世界:

  • 免费解析器
  • 经过战斗验证的向内容添加元数据的方法
  • 易于使用(取决于您定位的用户)
  • 您可以轻松提取原始文本,而无需元数据,因为它是XML解析器的标准功能。拥有内容的可索引版本非常有用,例如,Lorem <note>ipsum</note>在搜索时会出现这种lorem ips*情况。

为什么XML超过Markdown

像stackexchange这样的网站使用markdown作为其内容传达的语义是相当基本的:强调,链接/ URL,图像,标题等。似乎您要添加到内容中的语义是

  1. 更复杂
  2. 可能更改或必须可扩展

因此,我认为Markdown并不是一个好主意。而且Markdown并不是真正标准化的,解析/倾倒它可能会让人感到痛苦,更何况Markdown式的语法请参见Jeff Atwood在解析Markdown时遇到的有关WTF的帖子

关于数据和元数据之间的分离

本质上,这种分离不是强制性的。我认为您正在寻找它带来的优势:

  • 可以在没有元数据的情况下获得原始内容
  • 关注点分离:由于数据等原因,在处理元数据时,我不希望有副作用/复杂性开销。

通过使用XML消除了所有这些担忧。从XML中,您可以轻松转储任何剥离标签的内容,并且数据/元数据是分离的,就像XML中的属性和实际文本是分离的一样。

而且我也不认为你真的可以使元数据完全不与数据绑定。根据您的描述,元数据是数据的组成,即删除数据会导致元数据删除。这是元数据与通常的HTML / CSS不同的地方。删除html元素后,CSS不会消失,因为它可以应用于其他元素。我认为您的元数据中不是这种情况。

使元数据靠近数据(如XML或Markdown),可以轻松理解(甚至调试)数据。另外,您再三考虑的示例会增加一些复杂性,因为对于我正在读取的每个数据,我都需要查询元数据表以获取这些数据。如果您的数据和元数据之间的关系是1:1或1:N,则IMO显然毫无用处,只会带来复杂性(YAGNI就是一个很好的例子)。


我正在寻找的另一个优点是能够独立使用元数据,这意味着只查询元数据,而不必关心内容。为什么您认为1:n的关系数据:元数据显然“毫无用处”?
Sunyatasattva

让我们再添加一个案例,该案例使数据解决方案中的任何元数据都无法使用:我想使单个文本具有来自不同用户的元数据成为可能,该用户可能(也可能不)能够查看其他用户的元数据。
Sunyatasattva'3

我在新编辑中对此进行了详细说明。
Sunyatasattva

+1这正是SGML和XML设计的目的。
罗斯·帕特森

我认为一个问题是,据我所知,在XML中,碰巧在另一个元素内的任何元素都被视为该元素的元素,并且标记的重叠是不可能的(即,您必须在关闭父元素之前关闭元素))。在我的情况下,没有这样的层次结构,因为两个注解肯定可以重叠(在我的答案末尾添加了示例)。
Sunyatasattva

3

解决方案用例

我不同意其他一些答案,这仅仅是因为,虽然很好的解决方案,但它们可能不是您的解决方案。是的,XML的首字母缩写词是markup,但是对于您的情况,它可能不是理想的选择。它太复杂了,在将元数据与原始文本分开方面几乎没有帮助。从本质上讲,它将把所有内容变成一种元数据形式,从而创建一个超重的数据集。

由于可能没有绝对正确的解决方案或方法,因此最佳解决方案可以回答以下问题:

系统将如何使用数据?

另外,如果你试着问,怎么个解决方案设计本身可以添加到系统的价值,因为它会被使用的方式,那么你更接近于找到你优雅的答案。

了解问题

好的评论,让我们深入研究问题。据我所知,这是个问题(显然,添加问题将是有益的):

  • 有原文
    • 关于此原始文本的假设:
    • 此文本可能由也可能不由几个独立的文件组成
    • 一个或多个用户可能会或可能不会编辑此文本
    • 此文本包含相关信息。据此,我假设(如果我错了,请纠正我)元数据是相关的而不是描述性的。因此,它存储与原始文本相关的信息,而不是描述文本的信息。因此,将存储的笔记对原来的文本,而不是通过实例描述文本标题即大胆,一个网站等链接
    • 文本应易于过滤,与元数据不同
    • 应保护文本不被元数据破坏和破坏
  • 应该有一种方法来存储与原始文本(元数据)有关的信息
    • 此元数据还需要它自己的(元)元数据,该元数据将保存诸如元数据相关的信息,例如与元数据相关的用户(或组?),例如对元数据的描述,比如说它是注释或注释,或者说明等
    • 此元数据(及其(元)元数据)需要承受原始文本的更改,元数据的更改以及(元)元数据的更改
    • 元数据(+元元数据)需要结构良好且易于查询,并以关系方式索引甚至连接到其他数据集。元数据的关系性质不仅应限于查询,还应由于关系数据活动而促进元数据的更新或回写和更改。
    • 元数据(+ Meta-Metadata)的价值在于它非常相关的性质。一旦失去与原始文本的关系,它将立即适得其反。因此,与原始文本的完整关系是强制性设计的必要。
  • 关于问题的性质以及如何使用的其他假设是:
    • 并发异构系统访问。也就是说,用户可能希望在管理员(或另一个过程)对结构化元数据执行关系数据查询的同时查看文本并编辑元数据。
    • 系统将有几个用户
    • 该系统是现代的。也就是说,它不受存储空间,处理速度或实时命令的约束。与物理计算资源限制相比,完整性和针对特定目的的功能具有更高的优先级。
    • 随着系统的使用,系统的使用和功能可能(尽管很少)会有所发展或变化。

建立解决方案设计

了解了上面概述的问题后,我现在将开始提出旨在解决上述问题的可行解决方案和方法。

组件

因此,我将看到需要有一个定制的用户访问系统。它将从原始文本中过滤掉相关的元数据。这将有助于编辑和查看文本中的元数据。这样可以确保元数据与其原始文本之间的关系的完整性。它将构造元数据并为关系数据系统提供数据源。它很可能会提供许多其他目的驱动的功能。

结构体

那么既然对元数据的完整性保留原来的文字,在保证最好的方法是很重要的,是要保留元数据内嵌与原文。这样的好处是可以在不破坏完整性的情况下可靠地编辑原始数据。

这种方法的问题在于原始数据会破坏元数据,反之亦然。以允许查询和更新以及有效访问的方式,对元数据及其(元)元数据进行适当的索引和结构化。从原始文本轻松过滤元数据。

考虑到这一点,我建议解决方案的一部分应基于在原始文本中使用ESCAPE CHARACTERS的方法。这是一样的设计自己的标记语言或使用现有的标记语言,如XML或HTML。很容易设计出ESCAPE CHARACTER,其原始文本中存在零或几乎为零的机会。

在这方面,我的建议是仔细考虑原始数据,并尝试确定存储在其中的代码页的性质,然后寻找理想的CHARACTERCHARACTER SEQUENCE那是不可能或不可能发生的。例如,在ASCII中,实际上是内置控制字符,其字节值从未在标准用户界面中使用过。对于基于字体或基于关系数据的信息系统,可以说相同。请注意二进制数据编解码器。根据原始数据的性质,构建一个解析器来确认控制序列的发现可能很有价值,也许是通过查看转义的数据并验证其完整性,或者通过简单地检查转义的结构来进行数据,或者甚至包括为每个转义数据序列计算的控制字符。

带转义序列的示例数据

这是一个男人的故事。>>>>(#)为什么这个故事是关于一个男人不是一个女人?(#)()userid :: 77367()Manager's Comment()DataID :: 234234234 >>>>一个要割草的男人,去割草地。该名男子带着他的狗去了>>>>(#)问服务对象,如果用猫来代替故事会更好(#)>>>>去割草。所以现在这是一个男人和他的狗去割草的故事。

一个人和他的狗去割草,去割草,草地伸到了山上。>>>>(#)在森林中听起来更好(**)建议注释(#)>>>>

这个人和他的狗以及他的使命,要割草,只有过河时才能到达山上的草地。

没有转义序列的示例数据

这是一个男人的故事。一个人去割草地,去割草地。那人和他的狗一起去割草地。所以现在这是一个男人和他的狗去割草的故事。

一个人和他的狗去割草,去割草,草地伸到了山上。

这个人和他的狗以及他的使命,要割草,只有过河时才能到达山上的草地。

显然,这很容易解析,作为一个完整的标记语言并不复杂,并且很容易适应您的目的。

解决了吗? 好吧,我会说不。我们的解决方案仍然存在一些漏洞。此数据的索引编制和结构化访问很差。同样,在编辑该文件时同时查询一个(或多个)文件是不合理的。

我们如何解决这个问题?

我建议将数据分配表作为文档标题。我还建议实现一个TRANSACTIONAL TABLE UPDATE QUEUE。让我解释。文件系统(尤其是旋转磁盘文件系统)的设计人员面临着与您上面描述的类似的设计挑战。他们需要在磁盘上嵌入有关文件的信息以及数据。解决此数据的关系完整性的一个好方法是在文件分配表(FAT)中将其复制

这意味着对于每个单独的元数据项,在数据分配表中都有一个对应的条目。因此它是快速,结构化和相关的,并且独立于原始数据。如果需要对元数据执行查询,联接或更新,则只需访问数据分配表即可轻松完成。

显然,必须格外小心,以确保原始的内联元数据是数据分配表数据的真实反映。这就是事务表更新队列的来源。元数据的每次更改,添加或删除,都不在于其自身的数据上,而是在于队列上。然后,队列将确保对行内数据和表数据进行所有更改,或者根本不进行任何更改。它还允许执行异步更新,例如,可以通过在队列上运行删除命令来删除某个用户的所有元数据。如果内联元数据被锁定并在使用中,则队列将无法对表数据和内联数据都进行任何更改。


1
嗨,斯蒂芬,欢迎来到程序员!我感谢您的回答的热情,但我不得不删除不相关的评论。我们希望答案尽可能简洁,准确,切合实际,以便更广泛的受众使用。
扬尼斯

首先,我必须说我喜欢答案中的热情,很高兴听到如此好的反馈。至于答案本身,我必须说,我反对打开和关闭标签的相同语法。为了避免我在上面的最新更新中描述的XML问题,我将在代码本身中指定要打开的内容和要关闭的内容;也许像这样:>>>>>(#1) Lorem ipsum (#1)>>>>>>。另外,似乎您在intext注释中使用的方法是将它们绑定到某个固定位置,如果偏移量被移动,该方法将如何工作?
Sunyatasattva

此外,您将如何处理将注释绑定到偏移范围而不是精确点的事实?最后但并非最不重要的一点:数据分配表和事务更新队列似乎是令人惊奇的概念。我对这些主题进行了一些研究,但是您能否详细说明如何在此体系结构问题中实施这些概念?
Sunyatasattva

1

这是一种典型的工程问题,因为您的所有选择都有不同的权衡,而最好的选择取决于对您而言重要的因素。不幸的是,您没有提供足够的信息来做出决定。

您似乎也没有考虑过重要的语义问题。可以说原始文本是

我的朋友鲍勃借给我五美元

有人在“鲍勃”周围加了一条评论

鲍勃是个白痴

然后将原始文本编辑为

简借给鲍勃五美元,后来他借给我

可能会使用文本匹配算法(例如用于显示差异文件的算法)对这种特殊情况有所了解,但是字符偏移量将使元数据附加到“ Jane”中的“ Jan”。

更糟糕的是,如果将文本编辑为

我的朋友史蒂夫借给我五美元

您可以设法弄清楚如何将元数据附加到“ Steve”,但是如何知道它是否适用?

另外,您是否确定元数据本身是否可以包含元数据?那可能会改变您的实现。

除了语义问题,还不清楚您正在处理数据。我以为原始文本被任何标记“污染”可能是非常不便的,但是您可以在其中包含ID值。如果元数据应用于某个部分,这没有多大意义文本,而不是插入的文本点。

我的猜测是,对于大多数目的而言,存储标记的文本更容易,或者,第二选择,使​​用所有SQL并用节点层次结构表示文本和标记-本质上是表形式的DOM。如果您的数据是分层的,则使用XML和免费获得现有的解析器可能比编写自己的数据更容易。

很可能有一些相当简单的解决方案足以满足您的实际情况,但是我不能告诉您那是什么,因为它实际上取决于您要尝试做的事情的详细信息。

我强烈建议您尽可能多地封装您选择的任何策略,尽管如果许多SQL查询都需要看到很多实现,这很难做到。

抱歉,答复如此分散且充满“取决于”,但是现实世界中的设计问题就是这样。


我了解,我不是在寻找准确,正确的答案。但是对于实现的想法,权衡的分析,或者我认为有一个比其他答案更好的答案,而我只是没有想到。要回答您提出的问题:不,就我而言,元数据本身将不包含任何元数据。
Sunyatasattva

哪种更好取决于您要做什么。
psr

您认为我的问题中还缺少其他哪些细节才能给您清晰的画面?
Sunyatasattva

超出您能合理解释的范围。拥有一段文本相对于一个插入点的元数据有多重要,将文本一起保留在数据库的一个字段中有多重要,每个文本多久被编辑一次,将在直接SQL中分析多少查询与拉取文本,然后再进行分析,您对每种文本的舒适度是多少,发生在什么规模上,随着时间的推移可能会发生什么变化,如果您使用标记,是自己编写自己的简单解析器还是使用XML做得更好?定制程度较低,但具有更多工具...
psr

这就是为什么我只能提供准则。特别是因为答案旨在在类似情况下帮助他人,而不仅仅是您。
psr

0

我认为上一个回答者的建议(您在问题中提到的建议)是一个很好的建议。

它的行为与我们在StackExchange网站上发布链接的方式相同,但是信息数据将在另一个表上。好处是,您可以将数据分开,因此可以查询和建立索引。在编辑文本时,您可以检查已删除的元数据ID并清理元数据表。

像您说的那样,唯一的小问题是解析,但是您可以很轻松地处理它。


先前的答案是什么?不能保证所给出答案的顺序是任何顺序-或就此而言,答案可能会被彻底更改或删除,以使您的用处不大。您可以修改您的问题,使其不需要引用其他答案吗?

我的意思是,OP先前在问题中提到的答案
RMalke

0

可以说我有一段文字:

Lorem ipsum dolor坐下,管教着迷,sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat。

我添加如下注释:

Lorem ipsum dolor就座,秘密教规,sed diam [@ 123,#456,2w] nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat。

[@123,#456,2w]表示:user_id = 123,note_id = 456,此注释标记的文本跨越接下来的两个单词(可以是chars(c),句子(s),paragraps(p)等)。当然,确切的语法可能有所不同。

在纯文本编辑器中,便笺的文本可以很容易地存储在文档的末尾,就像Markdown脚注一样。

在富文本编辑器中,此类注释可以在文本中显示为图标,并且可以以某种方式突出显示标记的文本。然后,用户可以使用Del或删除这些注释,就像普通字符一样Backspace,并使用某种特殊的编辑模式对其进行编辑。我想象用鼠标调整注释区域的大小并使用弹出窗口编辑注释文本。

优点:

  • 与“交集”配合得很好,因为您标记了一个偏移量(隐式地由注释在文本中的位置表示)和每个注释的长度。
  • 支持多用户环境。(实际上,这需要进行更深入的研究,您可能不得不处理类似Google Wave运营转型的问题,我的大脑无法处理。)
  • 可以使用RTF和纯文本编辑器进行编辑。
  • 由于所有标记都就位,因此您可以轻松地进行修订-在标记之前编辑文本时,标记会随其他文本一起移动。
  • 易于解析。
  • 不需要外部数据库,但是如果需要,您仍然可以使用一个。
  • 如果您选择一些简洁的语法,则可以与Markdown或XML混合使用。

纯文本编辑的缺点:

  • 您看不到带有注释的文本区域(除非您突出显示纯文本,这也是一个选项),而只能看到注释开始的地方。这可以通过选择任意长度单位(字符,单词,句子,段落)的能力来弥补。
  • 您可以在注释下编辑文本而无需注意,尤其是在注释跨度很长的情况下(例如2个以上的段落)。可以通过修订控制机制进行补偿,该机制将每个便笺下的文本与以前的版本进行比较,并通知用户是否已更改。

一般缺点:

  • 有多个用户编辑同一文本的麻烦,但是无论如何我都认为这是不可避免的。我不是该领域的专家。

您认为不添加闭包标签而是使用偏移量的优点是什么?风险太大了吗?如果我在nonummy和之间添加一个单词怎么办nibh,会不会把我的偏移量弄乱?
Sunyatasattva

是的,这可能会产生偏移,并且可以在带有“虚拟”音符结尾标记的富文本编辑器中解决该问题,该标记符的行为与起始标记完全相同,不同之处在于它无法显式编辑(仅用于标记一个音符结尾,与编辑的文本一起移动),并且不会与文本一起保存。您只需在编辑时插入它,然后在保存时将其删除。通常,我认为开始标记和结束标记可能比仅其中之一存在更多的问题,但是我当然可能是错的。
scriptin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.