站內搜索
編輯推薦
本類下載榜
軟件簡介
Graph Engine是一款非常專業(yè)的數據處理引擎技術軟件。您需要好用的數據處理的引擎工具嗎?Graph Engine就是您最好的選擇。該軟件主要用于構建實時查詢應用和高吞吐量離線分析平臺,可以高效處理海量內存對象,與visual studio集成開發(fā)環(huán)境和azure無縫集成,給開發(fā)者帶來極佳的用戶體驗。歡迎從事開發(fā)的朋友前來jz5u!
1、Graph Engine的內存管理系統能高效處理海量內存對象。
2、作為一個高性能內存數據庫,Graph Engine可充分利用內存來加速數據訪問和并行計算。
3、作為一個通用計算引擎,Graph Engine擁有極強的可擴展性。
4、通過一個簡潔優(yōu)雅的數據和消息傳遞建模語言,Graph Engine允許用戶自由地定義數據模式和計算模型。
5、Graph Engine 還可與強大的集成開發(fā)環(huán)境Visual Studio以及微軟云計算平臺Azure無縫集成。
6、無論本地開發(fā)還是云端部署,Graph Engine都可以給開發(fā)者帶來極佳的用戶體驗。
7、開發(fā)者可以借助Visual Studio快速開發(fā),然后通過簡單的鼠標操作將一個分布式應用部署到云端。
首先,我們來回顧一下NOSQL中一種很重要的系統鍵值存儲器 (Key-Value stores)。Key-Value stores是一個字典形式的索引存儲系統,里面所有數據都按照Key去索引,每個Key對應一個唯一值。這就像是各種語言,如Python、Java中的Dictionary或者Map。
Graph Engine(數據處理引擎軟件) v1.0 官方最新版
比如MemCached,就是NOSQL中一個很早出現且非常流行的鍵值存儲器(Key-Value stores)系統。它是一個分布式、多線程的緩存系統。為什么叫緩存系統?因為它其實并不知道用戶存儲的數據結構是什么樣的,只是把數據當成一個個blobs,像二進制的數組一樣。這里的例子就是說,當給定一個Foo ID,我們利用MemCached,可以得出一個能夠識別的對象(Object)。但實際上MemCached本身無法識別我們這個東西,在它那里其實就是一個二進制的數組。
這所帶來的問題是,一個系統如果不知道用戶存的是什么東西,那么所有的計算就必須在客戶端進行。因為如果系統不知道數據的屬性,那就沒有辦法操作里面的數據。比如我有一個很大的對象,若要更新其中的一個部分,就需要把整個對象從客戶端輸入,然后進行一些操作再寫回去。當兩個人同時寫一個東西時,就可能會導致一個人的改動被另一個人的沖掉。
Redis系統比MemCached出現得晚一些,它支持幾種簡單的數據結構。系統中每一個Key對應的值可以是一個數據結構列表、集合或是字典。每一個值對應著一個小的容器,并且在這個容器上,它所有的操作都保持了原子性并支持事務。
但是在實際使用的過程中,我們會發(fā)現,很多時候數據沒有辦法簡單的用列表或字典這些簡單的數據結構來表示(因為它不能嵌入)。我們的數據有時候是層次結構的(Hierarchical)的,所以我們必須用某種層次化的數據結構,例如JSON、XML等去表示。在這種時候,Redis就沒有辦法很好地表達這些數據結構。實際上,業(yè)界很多用法都是用JSON模型先把它序列化成一個字符串,然后再輸入Redis。但這樣就會把Redis又變回MemCached,因為Redis不知道里面存的是什么東西,所以所有的計算操作又回到客戶端。
談到數據建模(DataModeling),我們不妨從另外一個角度,用圖數據庫去解決這種問題。在圖數據庫里,我們存儲的是實體間的關系。
舉個例子,左邊是一個表,右邊是和它等價的圖中的關系。我們可以看到這里有三個人,有老板,也有員工。老板會管理員工,員工也會為了某個項目向老板報告,這種數據模型最核心的數據結構就是圖。
圖由節(jié)點和節(jié)點間的邊構成。但這里的圖和教科書上講的圖有點不一樣,我們可以在點或者邊上添加一些數據,這種圖叫做帶屬性圖(Property Graph),即它的點上能夠存儲數據,比如說一個人的年齡、名字等等。在這種數據模型下,我們可以有一些在圖上的查詢方法,它能夠做到在SQL中很難表達的一些事情。
也正是因為這種靈活的特性,我們在實現圖數據庫時,會遇到一些挑戰(zhàn)。主要的問題是在查詢時,會有很多的隨機存取。因為在圖上查詢時,很多是利用遍歷實現的。雖然一個點走到另外一個點的代價不是很高,但是如果從一萬個點走到它周圍的兩萬個點,再走到周圍的四萬個點,這樣一層一層擴散出去的話,問題就會變得越來越嚴重。如果把數據放在磁盤上,就會有很高的時延,因為我們沒有辦法很好地預測一個點的下一步會決定往哪邊遍歷。
為了解決這個問題,有幾個主要的優(yōu)化手段。一個就是不要像SQL里,同一個實體需要在不同的表里面查找,更多的是直接把一個點上所有相關的信息組織在一起。所以只需查找一次,就能索引到其中的一個實體。另一個方法是,我們要盡可能多的把數據放在內存里,這樣隨機存取的性能會提高很多。
我們在做圖遍歷時,如果是單機系統,利用廣度優(yōu)先算法BFS或者深度優(yōu)先算法DFS都可以。但如果是分布式系統,由于不能跨機器執(zhí)行單機算法,所以我們需要用消息傳遞(Message passing)實現圖遍歷的功能。
圖數據模型下對應的查詢語言和傳統的SQL查詢語言會有一些不一樣。傳統上,如果在多個表里查詢數據,我們會用聯結操作(join operator)把數據連在一起。但是在圖查詢語言里,我們更多的是直接從一個點遍歷到它的鄰居,再從中篩選出符合條件的數據,做操作。
此外,在圖查詢語言里還可以使用一些特殊的操作符。比如,給定兩個點,然后可以查詢數據庫,找兩點之間的最短距離。我們還可以做一些特殊的便利操作,比如從一個點走出去,走過一個三角形,又回到這個點,這樣就可以找到這個點周圍的所有三角形。以及,告訴系統一直沿著某個條件走下去,就好像正則表達式一樣,直到遇到一個停止條件才停下來,我們把這個叫做閉包操作。
接下來我們看一個閉包的具體例子。假設Karl是部門的大老板,他會管理一些中層干部,這些中層干部會管理一些基層員工;而基層員工可能會在做一些項目,他們需要直接向Karl匯報?,F在在Karl管理的部門中,要找到所有向Karl直接匯報的人,應該怎么找?
這里的問題是,我們不能確定管理的鏈條有多長。因為可能是A管著B、B管著C、C管著D,D又向H報告。如果用SQL,就需要把所有的兩跳、三跳、四跳以及等等的操作都做一遍,最后再把結果綜合。但是在圖里面,由于有閉包操作,所以我們可以從Karl這個點出發(fā),沿著管理這條路線走,這樣走下去一定是報告和管理的關系,而終止條件是找到一個點,它不再管理其他人,或者是它連回了一條邊,比如Karl這條報告的邊。
剛才介紹了內存中系統以及Graph model怎么為數據建模,并且簡單介紹了圖數據庫上的查詢語句以及它是怎么做計算的。將這些內容結合,我們做了一個系統,就是Graph Engine,用于處理以上工作。
這里有一個系統結構示意圖,中間這個三角形是系統的基礎架構。最底層是一個內存中的鍵值存儲器(Key-Value stores),以及計算引擎。計算引擎在不同機器之間會傳遞消息,并且一個機器可以調用另一個機器上某一類消息的響應代碼(Handler)。在這種架構上構建圖模型層(Graph Model),用戶就可以利用圖模型層的抽象,做自己的應用。所以Graph Engine系統不僅可以進行圖數據的處理,由于它是分布式的,所以存儲管理(Memory management)做的也相對較好,可擴展性(Scalability)也比較好。此外它還具有一定的通用性,不僅是圖上的計算,還可以用于其他的應用。比如可以簡單的把它用作鍵值存儲器,簡單的定義數據結構,當成Redis去用。
在系統最底層, RAM store本質上也是一個鍵值存儲器,使用64位整數做Key,Value是任意的一個值。每個機器上有一個本地的RAM Store,不同的機器之間,給定一個Key之后,通過對這個Key進行Hash,可以判斷當前的實體,即Cell ID對應的Value是在哪個機器上。這是一種叫Share-nothing的配置方法。當然這是一個可配置的(Configurable)方案,但是默認情況下,它是一個Share-nothing的結構。
拿到一個Key,首先判斷它在哪個機器上,如果我們要訪問對象,就把這個消息發(fā)到那個機器上,機器訪問自己的本地內存數據。一個內存存儲(Memory store)可以分成很多不同的塊(Memory Trunk),里面有一套內存管理系統,所以我們最終可以定位到每一個對象所對應的內存區(qū)域。
講到這兒大家可能會有一個疑問。剛才說,如果把數據按照Blob二進制存的話會有些限制,可現在不還是把數據扔到一個內存塊里面,存儲為byte數組么?那接下來就講講我們是怎么處理這個問題的。
在Graph Engine系統中,我們使用Trinity Specification Language語言,即TSL,來完成以下三種功能。第一個,做數據建模,雖然存儲時存成的是一個Blob,但實際上我們有它的數據模式(Schema),并且可以由用戶指定,而不是用一些簡單的自帶數據結構。第二,在做Message passing時,如果期望得到某一種格式的回復,我們可以用TSL來定義消息傳遞格式。第三,系統和其他外部系統之間需要交互,比如要從C#里傳遞一個東西,放到Python里,我們也可以通過TSL來進行數據交換,我們可以提供一種標準,作為數據的中間格式。
這里有兩個TSL的例子,可以看到TSL和C族語言非常像。首先,看一下圖模型的定義,我們用Cell關鍵字,指明定義的結構體是一種實體實際上一個cell就是一個Key對應的一個Value,它有自己的內部結構。比如Movie里有電影名字,主演等。同樣的,根據演員名字,我們可以得出這個人演了哪些電影。
我們可以在實體的 Cell Type以及它的Filed上加一些屬性,用于和系統的其他模塊進行交互。在Message Passing里,實際上是一個類似的結構,我們可以定義一個結構,一個cell也可以包含一個結構,不過這個結構體還可以額外用來做Message Passing。
定義結構后,接下來,我們定義了一個通信協議,協議說,發(fā)送消息是同步消息,消息發(fā)出后,我期待對方處理完返回的還是一個My Message。
定義好TSL后,會有一個TSL編譯器,根據用戶定義的Cell Struct以及其他定義結構,生成一些對Cell操作的存取器(Accessor)。比如這里的UseMyCellAccesor,這個API不是系統本來提供的,而是Graph Engine的程序集(Assembly)加上用戶的TSL生成出的程序集然后再綜合生成的一個API。
這個API的使用方法和Struct類似,可以直接操作里面的ID,也可以認為里面Links是個List,直接分配給List一些值。但實際上我們并沒有分配一個運行時的List,我們會把操作翻譯成對當前Cell對應的內存的操作。也就是說鍵值存儲器負責最基本的給出內存空間。然后生成的代碼負責處理用戶如何分配數據,系統應該如何理解數據。
這樣一來,我們可以用像Struct一樣簡單的接口,利用Accessor,操作一個虛擬的概念。我們只提供了對操作的描述,具體的執(zhí)行則是翻譯成了低層對內存直接的操作。這樣既能保證用戶接口的友好性,工作效率也可以做得非常高。
另外,這也是Graph Engine與其他系統一個很顯著的區(qū)別,系統不僅可以對里面所存的實體進行類型定義,也可以有它自己的結構,甚至這個結構是分層的,因為一個Cell也可以包含其他的Struct。另一方面,由于擁有Accessor這套系統,因此,它可以直接在RAM Store里就地操作數據,從而相應地提高效率。
與此類似的,在用TSL做Message Passing過程中,我們從上圖的左上角看起,客戶端先初始化了一個請求服務器。在客戶端,Graph Engine只負責分配緩沖區(qū)(Buffer),然后生成的API就會有Data Accsesor告訴我們如何往緩沖中填充數據,甚至可以直接把RAM Store中的一些數據取出,再通過Accesor傳給服務器。在服務器這邊,我們有一個IOCP的線程池(Thread Pool),或者在Linux系統中,我們用的是一個事件庫。
并且我們還定義了協議(Protocol),每一個協議會對應一個Handler,代表服務器收到該協議的消息后應該做什么動作。我們把這個東西存成一個地址向量,在客戶端來了一個請求后,系統通過向量跳轉到一個Handler里去執(zhí)行。執(zhí)行完成后,根據消息是同步還是異步,可以做一個選擇。如果同步,客戶端會進行block,直到服務器處理完這個消息,并返回處理結果。
我們注意到,客戶端發(fā)送的請求ReqWriter以及服務器返回的RspReader,其實都是由TSL編譯器生成的。不僅如此,在一個消息到達服務器之后,它有一個調度(Dispatch)的過程,需要把消息翻譯成一種數據結構,這里我們可以直接用Data Accessor去讀取緩沖器中的內容。所有的輔助過程,包括Handler的抽象接口,都是由TSL Compiler生成的。我們設計系統的目標就是讓消息傳遞(Remote Message Passing)變得盡量簡單,就像在本地寫GUI程序一樣。
關于系統底層的實現細節(jié)就先介紹到這里。下面來看一個具體的例子做一個Twitter的爬蟲。Twitter本身提供了一組Streaming API,訂閱后會不停地給你推送最新的消息。
我們可以在Graph Engine上加一個Message Handler,每次Twitter來了一條新的消息,我們就向這個消息協議轉發(fā),這個協議(Protocol)可以是同步、異步,或者是內部的協議,也可以是HTTP的協議,所以和其他語言非常好交互。
Graph Engine(數據處理引擎軟件) v1.0 官方最新版
我們可以用這個做什么事情呢?當一條推文來了之后,我們可以把它放到Graph Engine里。在消息處理器中找到這條推文應該存的地方,比如,哪個用戶發(fā)的,提到了哪些人等等。在做這件事情的同時,實體間的關系就建立起來了,因為一個用戶發(fā)了一個推文,會有一個關系連到一條邊,如果推文里提到了其他人,那么系統就不僅是存下了這條信息,還可以把所有關系都實時建立起來。
不僅如此,在不停更新數據的同時,我們還可以在上面跑一些計算,記在數據庫里,并進行一些查詢。
Graph Engine(數據處理引擎軟件) v1.0 官方最新版
這里是一個簡化的Twitter 圖模型,里面有兩種實體,一種是用戶、一種是推文,我們用邊把它們連起來,發(fā)現用戶可能被其他的推文提到過。與此同時,關于推文的定義,它里面有一個單獨的邊,指向發(fā)推文的用戶,并且把文本內容作為一個屬性,附在這個點上。
比如,我寫好了一個Python的Twitter爬蟲,調用了官方接口,就可以去監(jiān)測Twitter中的事件,那么怎么交互呢?在Graph Engine里面定義一個協議(Protocol),標出期望的請求是一個Tweet Message,這里面就包含了用戶、時間戳、文本內容。因為這是一個事件定義,文本內容里可能是它發(fā)出的一個推文。在指定協議為HTTP后,Graph Engine啟動時候就會監(jiān)測一個HTTP的協議,然后我們就可以在Python里直接把數據傳送到Graph Engine。
上圖可以看到Post Tweet Handler的具體實現。首先從Python方來了一個請求,我們收到了一個推文消息,然后就可以實時在Handler里用正則表達式看有沒有提到用戶名的部分。如果有,就抽取出來,變成User ID,然后填充相應的關系。以及在此之后,我們會把當前推文存到系統里面。因為Handler不是單線程的調用,系統有一個thread Pool,所以這樣的操作可以在一個Handler里實時完成。
更進一步,在不停的接收(Ingest)數據的同時,還可以定義另外一個協議。現在如果要做全文索引,就可以看到定義了協議后域名下就會多出一個SearchTweet的地址,如果用一個Python代碼去訪問這個地址,就會觸發(fā)SearchTweetHandler。這里可以使用LINQ語法,localstorage代表要用自己機器上的RAM Store。后面的Selector是說一旦使用Tweet_AccessorSelector,就會把所有推文全部選出來,再之后就可以用where做過濾(filtering)。比如,文本里有請求的查詢內容,滿足條件我們就做一個投影(projection),取出Cell ID,然后我們就拿到了所有符合搜索的推文。
那么問題也來了。Schema是用戶自定義的,這里可能包含任何東西,在這種情況下,如何設計一個標準的圖模型層?為此,我們采取了一個方案,就是把整個系統做成一個模塊化系統(Module System),每一個模塊可以提供一個泛型算法(Generic Algorithms),它不和某個具體數據綁定,而是根據某種元規(guī)則執(zhí)行算法,類似C++里面模板庫做的事情。
只要泛型算法對于一個數據的觀點、看法和用戶對于數據的看法一致,那么就可以說用戶數據的schema和某個泛型算法是兼容的,進而用戶就可以實現一個通用的圖模型來完成一些他不方便自己實現的功能。
具體來講,回到剛才的Tweet Graph上,我們有用戶和推文兩種實體。我們的目標是要把查詢語言,就是LIKQ,應用到Tweet Graph,在Tweet Graph上實現圖的查詢。問題是現在的Schema里只有List,系統不可能見到List就認為它是一個邊,然后去遍歷,因為這個Long可能還有別的意思,這樣是不現實的。
為了解決這個不匹配問題,我們可以加一些屬性。這里的屬性是TSL里面的,和C#里是不一樣的,可以理解成是一個字符串,我們把字符串的標簽(tag)打在了一個實體或者field上。這里打的標簽叫做 GraphEdge,這樣就指定了,它是圖里面的邊。這就回到了剛才所討論的,數據和泛型算法對于一個屬性有沒有統一的認識。比如,如果查詢語言覺得GraphEdge是邊的意思,那么它就會采取一個方案。如果是一個算法的模塊調用一個具體的名字,如遍歷判斷當前是不是一個用戶。如果是用戶就從Tweets mentioned_by走過去,那這樣就不是泛型算法,因為它引用(reference)一個具體的數據。
為了避免這種情況,我們允許泛型算法直接通過屬性,找到一個實體中所有符合屬性的部分。它可以請求系統,去當前的實體里尋找所有有GraphEdge標志的部分,并且目標是想從這里面提取出長整型。所以不管你的GraphEngine是List,還是單獨的Long,甚至是一個Int,更有甚者,這里存的是個String,都可以通過我們系統的Graph Model中間層,然后盡可能的枚舉(Enumerate)出長整型來,使得用戶數據和系統的泛型算法間可以聯系在一起。
接下來我們看一下具體的圖查詢語言,即LIKQ 。LIKQ是一個直接可以嵌入編程語言的查詢語言,它和LINQ很像,都有一個很流暢的語法,可以直接寫在編程語言里。
這里的例子是一個知識圖譜,StartFrom這個點,指定一個查詢條件,名字叫比爾蓋茨,從這個點FollowEdge,就說從人這個點走到他的職業(yè),然后再從FollowEdge走到people_profession_people_with_this_profession,就找到了和他相同職業(yè)的所有人。
我們不僅可以簡單從每條邊走出去,同時可以在一個點上時時的添加一些查詢條件,方法是給這個點傳入一個Lambda表達式,每當遍歷的框架遇到這個點,比如走到第三跳時,就會動態(tài)執(zhí)行這個Lambda表達式。
比如這里的例子是找和比爾蓋茨相同職業(yè)的,會說三種以上語言的人。如果找到了,系統就保存當前路徑(Path),否則就終止當前的搜索。
Lambda表達式具有非常靈活的查詢(Query)特性,不僅可以調用Count>3,用戶甚至可以預先把自己的一些功能注冊到LIKQ模塊里,只要服務器配置正確且加載了程序 (assembly),客戶端就可以直接調用這個接口,調用服務器上預先存好的邏輯,而不用把整個邏輯全部寫到Query里面。
易語言v4.05修訂版 簡體中文特別版_易學易用的漢語編程語言
WinHex16進制編輯器19.3 漢化綠色版
Microsoft Visual FoxPro 6.0簡體中文免安裝版【可視化編程工具】
PHP For Windows 7.3.9 官方安裝版
UltraEdit(文本編輯器)21.20.1001.0 烈火漢化增強版
WinHex(16進制編輯器)19.8 SR-4 中文綠色版
Java SE Runtime Environment 9.0u177 x64 官方安裝版
易語言(支持基于漢語字和詞編程) 綠色精簡版
PSPad editor V5.0.2(321)中文綠色版
EXE資源查看提取器_Resource Explorer 漢化綠色版
Source Insight 4.0 漢化綠色版_功能強勁的程序編輯器
網絡編輯超級工具箱(文章快速格式化) v1.2綠色加強版
匯編指令助手查詢器 (匯編指令大全)V1.1 綠色版
UltraEdit 21.20.1009.0烈火漢化綠色版
UltraEdit-32 15.00.0.1042簡體中文綠色便攜版
Hex Workshop x64(bin文件編輯器)V6.7.25284 漢化版