2015-10-02 23 views
3

我試圖在內存中保留由下面的模式標識的一組數據結構。我有一個粗略的解決方案,但我正在尋找一些更好的想法。性能和可靠性至關重要,記憶力不是很大(在合理範圍內),因爲表格非常小​​(最多有幾百個條目,更可能是幾十個)。我想,我寧願不使用內存數據庫來處理這樣一個小數據集。使用散列表的關係數據

enter image description here

我試圖做到的是快速查詢基於A.Name所有的B項的能力,所有的參賽作品基於B.Name,或基於T.Tag所有的參賽作品(我目前並不需要基於T.Tag的所有B條目,但在將來可能會有用)

目前我使用三張帶有重複數據的表,以及帶來的同步問題,以及當我一個新的數據,我存儲它三種不同的方式。我相信必須有更好的方法。

// all A entries matching a tag 
val Tag2A= new MutableHashMap[String, MutableSet[String]]() with MutableMultiMap[String, String] 

// all B entries matching a tag 
val Tag2B = new MutableHashMap[String, MutableSet[List[Int]]]() with MutableMultiMap[String, List[Int]] 

// all Tags matching a A entry 
val A2Tag = new MutableHashMap[String, MutableSet[String]]() with MutableMultiMap[String, String] 

有人可以推薦一個更優雅的解決方案嗎?編輯:(澄清)我的MutableMultiMap和MutableSet只是mutable.MultiMap和mutable.Set在導入時別名。

EDIT2:表格需要修改(添加/刪除)。

回答

1

假設你可以將所有內容加載到內存中,不變的解決方案是可以接受的:

abstract class A2B(tag: String) { 
    def aMap: Map[String, A] 
    def bMap: Map[String, B] 
} 

case class A(id: String, name: String, tag: A2B, payload: String) 

case class B(id: String, name: String, tag: A2B, payload: List[Int]) 

您可以像初始化(解決chicken-egg problem):

def getA2b(name: String): A2B = new A2B(name) { 
    val aMap = { //you can query your external data source tableA here 
     val a1 = "a1" -> A("a1", "a1", this, "aaaa") 
     val a2 = "a2" -> A("a2", "a2", this, "aaaa") 
     Map(a1, a2) 
    } 

    val bMap = { //you can query your external data source tableB here 
     val b1 = "b1" -> B("b1", "b1", this, Nil) 
     val b2 = "b2" -> B("b2", "b2", this, Nil) 
     Map(b1, b2) 
    } 

    override def toString = name 
} 


val a2b = Map("a2b1" -> getA2b("a2b1")) //you can query your external data source tableA2B here 

和在不斷的訪問時間查詢(對不起,現有機器上還沒有Scala REPL):

println(a2b("a2b1")) 
println(a2b("a2b1").aMap) 
println(a2b("a2b1").aMap("a1").tag.bMap) 

a2b1                                                             
Map(a1 -> A(a1,a1,a2b1,aaaa), a2 -> A(a2,a2,a2b1,aaaa))                                                 
Map(b1 -> B(b1,b1,a2b1,List()), b2 -> B(b2,b2,a2b1,List())) 

這裏的所有關係都是用鏈接建模的,所以沒有開銷。該結構是不可變的,所以它是線程安全的。你也可以注意到A2B類在構造函數中被初始化(並且所有的vals默認是最終的),所以根據JSR-133沒有同步問題 - 你的應用程序總是看到A2B的最終版本,所以不需要揮發性物質。

+0

謝謝,這有助於。我看到的唯一限制是我的數據來自一個流,因此我無法立即將所有內容加載到內存中。因此數據集將在流的整個生命週期內進行修改(添加/刪除)。我意識到我沒有在我的問題中包括這一點,我很抱歉。我正試圖修改你的答案以支持這一點,但我的雞肉正在與我的雞蛋搏鬥。 –

+0

@WillIAm如果你的數據集非常小,而且你不關心數據源開銷 - 如果事情發生了變化(或者甚至不是所有的事情),只要在新的a2b基礎上增加delta就可以重新加載所有內容(a2b) - make確定它是原子的,然後在a2b上沒有併發更新)。只要你的數據是隻讀的並且最終一致的 - 你就不會有任何「var a2b =」的併發問題。在強一致性的情況下,你可以使用Actor(或代理)或者將不可變的a2b隱式地傳遞給所有函數(如果下一個消息適合你,它們將獲得新數據)。 – dk14

+0

謝謝。我需要弄清楚如何將這與我的演員相結合(我在一個演員中,而我的變化就像演員所說的那樣),但它看起來就像我需要的東西。從演員Receive塊修改這些映射的最有效方法是什麼? –