我在mongoDB中有一组东西(基因(。我正在做一个分析,看看每个基因与其他基因的相似程度,我想把这些信息存储在数据库中。我目前在数据库中为每个基因提供了不同的文档,其中包含诸如基因来自哪个物种和DNA序列之类的信息。当然,每个都有一个唯一的标识符_id
。
当我进行分析时,我将按百分比(它们的perc_identity
(获得有关相似基因的信息。通常,分析可以返回的下限是~70%,因此每个基因不一定有一个数字,但每个关系都是相互的(例如,如果perc_identity(A:B) == 90
则perc_identity(B:A) == 90
(。
我的问题是存储这些关系的最佳数据模型是什么,以便我可以检索它们以进行进一步分析?换句话说,有时我会想抓住所有perc_identity > 95
对。其他时候,我会想要获得特定基因的所有匹配项。如果很重要,获得perc_identity
的初始分析只需要执行一次,并且已经花费了相当长的时间,因此插入的性能不如检索以后分析重要。
我的一些想法(如果这很重要,我正在python中使用mongoDB(:
1(在每个基因的文档中,有一个子文档,其中包含所有匹配的_id
及其perc_identity
。例如:
{
_id: geneA,
dna_seq: 'AACTG...',
species: 'Homo sapiens',
hits:{
geneA: 100,
geneB: 92,
geneC: 70,
}
},
{
_id: geneB,
dna_seq: 'AATTG...',
species: 'Pan troglodytes',
hits:{
geneA: 92,
geneB: 100,
}
},
{
_id: geneC,
dna_seq: 'ATGGC...',
species: 'Homo erectus',
hits:{
geneA: 70
geneC: 100
}
}
这显然会导致一些数据重复,但这最接近于数据从初始分析中吐出的方式。大多数时候,我不会关心gene
文档中的大多数其他数据,所以我不清楚将信息嵌套在其中是否会减慢速度。我也不清楚是否有一种有效的方法来查询,例如,所有perc_identity > 90
.每次我想进行分析时,我都会检索到我需要的双倍数据量。
2(有一个单独的文档,只包含基因_id
s及其所有命中。例如:
{
_id: 'hits',
geneA: {
geneA: 100
geneB: 92
geneC: 70
},
geneB: {
geneA: 92
geneB: 100
},
# etc
}
这样做的好处是我根本不用弄乱基因文件。如果这有什么不同,我也可以有一个不同的hits
收藏。另一个好处是会有~50k个基因记录,但其中只有大约1-2%会有任何点击,所以查询不必费心检查大多数文档。否则,这对我来说似乎与(1(非常相似。
3(某种没有冗余的方法。我想不出做到这一点的好方法。我想到的糟糕方法是让perc_identity
成为键,然后有一个_id
元组的列表。我可以四舍五入到最接近的整数百分比。似乎这需要在每次插入某些内容或插入所有内容然后折叠集合时检查特定perc_identity
内每个元组中是否存在_id
。在这种情况下,检索特定_id
的所有匹配项似乎效率非常低。
或者,由于顺序无关紧要,例如:
{
_id: ?
type: 'hit'
pair1: geneA
pair2: geneB
perc_identity: 92
},
{
_id: ??
type:'hit'
pair1: geneC
pair2: geneA
perc_identity: 70
},
# etc
对这些
策略之一的任何批评,或对其他表示方式的建议将不胜感激。如果还有其他信息,或者我可以澄清任何事情,请告诉我。如果 (1( 或 (2( 似乎是好的策略,我想我唯一的问题是基于某个perc_identity
阈值构建查询的最佳方法。
这从来都不是一个容易回答的问题!但是,指导原则应该是根据您打算使用数据的方式做出决定。在本例中,您提到了两个查询:
- 用
perc_identity > 95
抓住所有的对 - 获取一个基因的所有匹配项
(当然,您可能还计划进行其他常见的分析,这将有助于阐明它们。
基于此,我鼓励你采用一种非规范化的方法,就像你在第三种选择中讨论的方法一样。它确实有一些缺点,主要是在插入方面,您似乎已经意识到了这一点,但它使第一种类型的查询变得非常容易:
db.hits.find({perc_identity: {$gt: 95}})
。而使用任何其他方法,您需要迭代其他文档中的所有键。例如,使用第一种方法,您需要检索每个基因的hits
子文档,迭代这些子文档的键,并将大于 95 的子文档添加到列表中。这需要从mongodb/pymongo中完成。
另一个查询比方法 1 和 2 更复杂,但不是很多:
db.hits.find({$or: [{pair1: <your gene>}, {pair2: <your gene>}]})
因此,以插入上更多的逻辑为代价,您提到的两种查询情况变得非常简单,并且可以由数据库服务器本身轻松处理。如果你有其他常见的用例,你的第三种方法很难实现,那么值得重新审视它 - 但就目前而言,这就是我会选择的。
两个注意事项:首先,MongoDB的文档有一些关于数据建模的好建议,可能值得一读。其次,尽管我喜欢MongoDB,但鉴于我对你的问题域知之甚少,这可能是关系数据库可能更适合的一种情况。