为NoSQL设计数据模型的功能

介绍


“您需要以保持原位的
速度运行但是要到达某个地方,您必须运行至少两倍的速度!”
(c)爱丽丝梦游仙境


前段时间,我被要求就设计数据模型的问题我们公司的分析师进行一次讲座,因为当我们长时间坐在项目上(有时是几年)时,我们看不到IT领域正在发生的事情。在我们公司(只是这样),NoSQL数据库并未在许多项目中使用(至少到目前为止),因此在我的演讲中,我使用HBase示例分别关注了它们,并尝试将材料的介绍定位于工作了。特别是,我用几年前在Amandeep Khurana的文章“ HB ase Schema Design简介”中阅读的示例说明了数据模型设计的一些功能。通过分析示例,我比较了解决相同问题的几种方法,以便更好地向听众传达主要思想。


我想知道,最近“无事可做”(在隔离模式下的五月长周末特别适合这样做),多少理论计算将与实践相对应?实际上,这篇文章的想法就诞生了。已经使用NoSQL数天的开发人员可能不会从中学习到任何新知识(因此可以立即花半百)。但是对于尚未与NoSQL紧密合作的分析师,我认为这对于基本了解HBase数据模型的设计功能将很有用。


解析一个例子


我认为,在开始使用NoSQL数据库之前,您需要仔细考虑并权衡利弊。通常,最有可能在传统的关系型DBMS上解决该问题。因此,最好不要在没有充分理由的情况下使用NoSQL。但是,如果决定使用NoSQL数据库,则应注意此处的设计方法有所不同。特别是其中一些对于以前只处理关系型DBMS的人可能是不寻常的(根据我的观察)。因此,在“关系”世界中,我们通常从对域进行建模开始,然后只有在必要时才对模型进行归一化。在NoSQL中,我们必须立即考虑使用数据的预期方案。并首先对数据进行非规范化。另外,还有许多其他差异,将在下面进行描述。


考虑以下“综合”问题,我们将继续处理该问题:


有必要设计某个抽象社交网络的用户好友列表的存储结构。为简化起见,我们将假定我们所有的连接都是定向的(如在Instagram中,而不在Linkedin中)。该结构应允许有效地:
  • 回答用户A是否正在读取用户B(读取模板)的问题
  • 如果从用户B订阅/取消订阅用户A,则允许添加/删除链接(数据更改模板)

, . (, , , , : , .., «»), /. :


user_idfriend_id

ID


HBase , :


  • , full table scan,
    • , SQL- – ; , , Impala SQL- Join’ HBase, …

ID . « ID ?» . «» ( 1 (default), ):


RowKey
1:2:3:
1:2:

. : 1, 2, … — , ID . , . (1, 2 3), – (1 2) – HBase, :


  • ( -> , -> )

:


  • : , , , RowKey = «» , «» . , « » False;
  • : : RowKey = «», . - , , ID .
  • : :
    • RowKey = «» , , ;
    • , , «» , «» .

, , « », , -. n. (n-1). (-1) , - .


  • : . (n)
  • : : , => (n)
  • : :
    • – => (n)
    • «» . « », (n-1) . , «-» - – n. ( , (2)) (n) . : «» , , :

, O(n).
, , , , - . «count», . - , «count». , «count» . .. 2 (count):


RowKey
1:2:3:count: 3
1:2:count: 2

:


  • : « ?» => (n)
  • : : , , «count» .. . (1)
  • : : , - «» . , , , => O(n)
  • , «count», , -

2 , « ». «» 3 (col).
« »: ! – , 1 (, , , «// ..»). «», NoSQL-, HBase :


RowKey
: 1: 1: 1
: 1: 1

. , :


  • : , , , «»: , True, – False => O(1)
  • : : : «ID » => O(1)
  • : : «ID » => O(1)

, , , , . , …


- . ? userID.friendID? ( 4(row)):


RowKey
.: 1
.: 1
.: 1
.: 1
.: 1

, , (1). 3 - .


«». , 4 , , , ( , HBase ). , . , userID friendID, , , . ( 5(hash)):


RowKey
dc084ef00e94aef49be885f9b01f51c01918fa783851db0dc1f72f83d33a5994: 1
dc084ef00e94aef49be885f9b01f51c0f06b7714b5ba522c3cf51328b66fe28a: 1
dc084ef00e94aef49be885f9b01f51c00d2c2e5d69df6b238754f650d56c896a: 1
1918fa783851db0dc1f72f83d33a59949ee3309645bd2c0775899fca14f311e1: 1
1918fa783851db0dc1f72f83d33a5994dc084ef00e94aef49be885f9b01f51c0: 1

, , , 4 – (1).
, :


1 (default)O(n)O(n)O(n)
2 (count)O(1)O(n)O(n)
3 (column)O(1)O(1)O(1)
4 (row)O(1)O(1)O(1)
5 (hash)O(1)O(1)O(1)

, 3-5 . , , , «», « ». 3. , , .



– . « » , (n). , , , « », «-». «-» :


  • ,

, , :


  • . n. " " – . , « » HBase . – «-»
  • . «», , . = - , «», – «». , «» «» ( 1 2). .
  • . . – ( «» , ). .

5 , , . n , , 5 .
n= 5. «» ID-:



{0: [1], 1: [4, 5, 3, 2, 1], 2: [1, 2], 3: [2, 4, 1, 5, 3], 4: [2, 1]} #  15 

{0: [1, 10800], 1: [5, 10800, 2, 10801, 4, 10802], 2: [1, 10800], 3: [3, 10800, 1, 10801, 5, 10802], 4: [2, 10800]} #  18  

{0: [1], 1: [1, 3, 2, 5, 4], 2: [1, 2], 3: [4, 1, 2, 3, 5], 4: [1, 2]} #  15 

, ID, 10 000 – , False. , «» .


Windows 10, - HBase, – Python Jupyter Notebook. 2 CPU 2 . , « », «» Python. HBase happybase, (MD5) 5 — hashlib


n = 10, 30, …. 170 – ( n) - ( 15 ).


, . . n, « » , «» , ( ).



– , . – .

3-5 «-», .
2 , , 2 3-5. , – - / HBase 2 . , .
1 , .
.

3-5 – , . 1 2 . 2 – - «count», n . - , . , ( , 1 2, ) ( " ").


– .



. 3-5 .
, , 4 5, , , 3. , – , , .


1 2, , . 2 1 – - - «» count.


:


  • 3-5 , HBase; .
  • 4 5 . , 5 . , .
  • , «-» , .


. , ( ). , thrift, happybase, , Python ( , ), HBase, Windows 10 .. , . « » .


总结-对刚开始在HBase中设计数据模型的任何人的建议:从以前对关系数据库的经验中抽象出来,并记住“诫命”:


  • 在设计时,我们从任务和数据操作模式出发,而不是从领域模型出发
  • 有效访问(无全表扫描)-仅按密钥
  • 非规范化
  • 不同的行可能包含不同的列
  • 列的动态组成

All Articles