5-Answer 系列-本體查詢模塊

前面幾篇已經(jīng)介紹了本體構(gòu)建模塊廓脆,運(yùn)行本體構(gòu)建模塊可以構(gòu)建出一個(gè)初步的本體庫宛瞄。

在構(gòu)建出本體庫之后,我們該如何對它進(jìn)行操作呢肝匆?

這一篇介紹本體查詢模塊。

SPARQL

大多數(shù)程序員在日常開發(fā)中接觸最多的應(yīng)當(dāng)是關(guān)系型數(shù)據(jù)庫顺献,例如 MySQL、Oracle枯怖、SQL Server 等注整。這些關(guān)系型數(shù)據(jù)庫使用標(biāo)準(zhǔn)的結(jié)構(gòu)化查詢語言 SQL 來實(shí)現(xiàn)對數(shù)據(jù)的查詢和更新等操作。

雖然不同數(shù)據(jù)庫以及同一數(shù)據(jù)庫不同版本對 SQL 語言規(guī)范的支持和實(shí)現(xiàn)都有所不同度硝,不同數(shù)據(jù)庫在 SQL 上的語法也會有細(xì)微的差別肿轨。但是 SQL 語言已經(jīng)極大降低了數(shù)據(jù)庫的學(xué)習(xí)成本,其非過程化蕊程、自然語言風(fēng)格等特點(diǎn)極大提高了我們操作關(guān)系型數(shù)據(jù)庫的效率椒袍。

從關(guān)系型數(shù)據(jù)庫回到我們的本體庫(RDF數(shù)據(jù)庫),自然很容易聯(lián)想到針對采用 RDF 框架的數(shù)據(jù)庫也應(yīng)該有一套相應(yīng)的查詢操作語言藻茂。

SPARQL(全稱 SPARQL Protocol and RDF Query Language) 就是我們需要的針對 RDF 的查詢語言驹暑,它提供了查詢 RDF 數(shù)據(jù)庫的能力玫恳,并在 2008 正式成為 W3C 的推薦標(biāo)準(zhǔn)語言。2013 年更新至 SPARQL 1.1优俘,SPARQL 1.1 提供了更為強(qiáng)大的能力京办,添加了例如更新、查詢嵌套等操作帆焕。

小栗子

假如現(xiàn)在本體庫中存有如下三元組:

美人魚 有導(dǎo)演 周星馳

現(xiàn)在如果想要查詢 "美人魚的導(dǎo)演是誰"惭婿,那么可以通過如下代碼實(shí)現(xiàn):

SELECT ?name
WHERE {
  美人魚 有導(dǎo)演 ?name
}

其中 SELECT 和 WHERE 不必多說,值得注意的是 WHERE 子句中的內(nèi)容叶雹。之前已經(jīng)提到了資源描述框架中 RDF 中數(shù)據(jù)的表達(dá)單位是一個(gè)三元組——(subject,predicate,object)财饥,即主體-謂語-客體。因此在進(jìn)行查詢時(shí)也以三元組的形式給定查詢條件折晦,在查詢條件中钥星,三元組中三元素的任意一個(gè)都可以設(shè)定為變量。

例如現(xiàn)在如果要查詢周星馳導(dǎo)演過哪些電影筋遭,可以這些設(shè)定變量:

SELECT ?movie
WHERE {
  ?movie 有導(dǎo)演 周星馳
}

以上代碼就可以列出當(dāng)前本體庫中存有的所有周星馳導(dǎo)演的作品打颤。

再進(jìn)一步如果想要查詢美人魚導(dǎo)演的年齡,可以實(shí)現(xiàn)如下:

SELECT ?age
WHERE {
  美人魚 有導(dǎo)演 ?a.
  ?a 有年齡 ?age.
}

從中可以看到通過相同變量來標(biāo)識同一實(shí)體漓滔,這樣可實(shí)現(xiàn)連接的效果编饺,查詢可表示為"美人魚 -> 導(dǎo)演"、"導(dǎo)演 -> 年齡"响驴,連接為 "美人魚 -> 導(dǎo)演 -> 年齡"透且。

當(dāng)然以上的查詢語句是一種簡化,是為了方便表達(dá) SPARQL 的基本含義豁鲤。再考慮上語法細(xì)節(jié)秽誊,應(yīng)該實(shí)現(xiàn)如下:

PREFIX mymo: <http://www.semanticweb.org/narutoku/ontologies/2016/3/my-ontology#>

SELECT ?name
WHERE {
  mymo:美人魚 mymo:有導(dǎo)演 ?name
}

之前提到過本體應(yīng)該具有共享的特點(diǎn),而且 RDF 很重要的一個(gè)應(yīng)用就是語義網(wǎng)琳骡。

因此我們構(gòu)建的本體庫應(yīng)該要考慮到與他人共享锅论、避免沖突等問題,這就需要為我們本體庫中的實(shí)體以及關(guān)系等設(shè)定唯一標(biāo)識楣号。我們的 "美人魚" 實(shí)體應(yīng)該表達(dá)為最易,"標(biāo)識: 美人魚", 在 Answer 系統(tǒng)中這個(gè)標(biāo)識就是 <http://www.semanticweb.org/narutoku/ontologies/2016/3/my-ontology#>炫狱。

所以在構(gòu)造 SPARQL 查詢語句的時(shí)候需要在每個(gè)實(shí)體和關(guān)系前面添加 <http://www.semanticweb.org/narutoku/ontologies/2016/3/my-ontology#>藻懒,為了方便可以使用 PREFIX mymo : <標(biāo)識> 簡化,如上代碼所示视译。

另外在系統(tǒng)實(shí)際代碼中是不會直接用 "美人魚" 來查詢的嬉荆,因?yàn)橹耙约疤岬竭^ "美人魚" 存在同名實(shí)體和實(shí)體別名的情況,所以最終會使用實(shí)體 ID(在構(gòu)建本體庫生成 UUID 作為實(shí)體或關(guān)系的唯一標(biāo)識)來查詢酷含。而同名實(shí)體的識別或?qū)嶓w別名的消歧在構(gòu)建查詢語句之前完成鄙早,這一部分會在語義解析模塊中介紹汪茧。

以上是對 SPARQL 極短的介紹,畢竟 SPARQL 語言不是一篇博客就能介紹的完的蝶锋。文章的末尾給出了一些關(guān)于 SPARQL 的參考資料陆爽。

使用 Jena

上面已經(jīng)介紹了 RDF 數(shù)據(jù)查詢語言 SPARQL。雖然 SPARQL 和 SQL 一樣具有易學(xué)易用的特點(diǎn)扳缕,是非常強(qiáng)大的工具慌闭。但是如果在每一次的應(yīng)用開發(fā)中,針對每一次的數(shù)據(jù)查詢需求都要反反復(fù)復(fù)編寫 SPARQL 語句還是顯得有點(diǎn)麻煩躯舔,尤其是在一些簡單但又頻繁使用的操作場景驴剔,例如添加一個(gè)實(shí)體、或添加一個(gè)屬性粥庄、又或向一個(gè)實(shí)體添加一個(gè)數(shù)據(jù)屬性等等丧失,這些操作需求頻繁出現(xiàn),重復(fù)編寫 SPARQL 語句十分不必要惜互。

這時(shí)候就輪到 Jena 出場了布讹。Jena 是 Apache 軟件基金會開源的 RDF 數(shù)據(jù)查詢框架,它是對 SPARQL 語言規(guī)范的實(shí)現(xiàn)训堆,是對 SPARQL 一些基本操作的封裝描验。利用它提供的豐富的 API 就可以實(shí)現(xiàn)對本體庫進(jìn)行各種操作。

例如如果想要添加一個(gè)實(shí)體坑鱼,可使用:

/**
  * 創(chuàng)建實(shí)體
  * 根據(jù) UUID 和所屬類 創(chuàng)建一個(gè)實(shí)體
  * @param individualId 實(shí)體 ID 
  * @param genusClass 實(shí)體類型
  * @return
  */
public Individual createIndividual(String individualId, OntClass genusClass);

給一個(gè)實(shí)體添加數(shù)據(jù)屬性:

/**
  * 給實(shí)體添加單個(gè)數(shù)據(jù)屬性
  * @param ontologyClass
  * @param individualId 實(shí)體標(biāo)識
  * @param propertyName 屬性名
  * @param propertyValue 屬性值
  * @return
  */
public boolean addDataProperty(Individual individual, String propertyName, String propertyValue);

查詢實(shí)體是否存在:

/**
  * 查詢實(shí)體是否存在
  * @param individualName
  * @return
  */
public boolean individualExist(String individualName);

Jena 還提供了其它非常多功能強(qiáng)大的 API膘流,更多更詳細(xì)的 API 可查詢 官方 API 文檔

Jena 官方站點(diǎn) 也給出了 Jena 的教程等相關(guān)參考資料鲁沥。

數(shù)據(jù)訪問封裝

有了 SPARQL 和 Jena 之后呼股,我們就可以對本體庫進(jìn)行基本的操作。有了這些基本操作画恰,我們就可以在這之上對業(yè)務(wù)層面的數(shù)據(jù)訪問需求進(jìn)行封裝彭谁。

比如在語義解析模塊中進(jìn)行實(shí)體別名消歧(星爺-消歧成-周星馳)的時(shí)候就需要查詢本體庫中的等價(jià)實(shí)體——查詢 "星爺" 是否有等價(jià)實(shí)體,查詢本體庫發(fā)現(xiàn) "星爺" 等價(jià)實(shí)體 "周星馳"允扇,則返回 "周星馳")缠局。我們就可以將這個(gè)同名實(shí)體的數(shù)據(jù)查詢需求做一個(gè)封裝。

所謂本體查詢模塊就是對 Answer 系統(tǒng)中諸如上述 "查詢等價(jià)實(shí)體" 的數(shù)據(jù)訪問需求的封裝蔼两。

以 "查詢等價(jià)實(shí)體" 為例,代碼如下:

public String querySameIndividual(String individualName) { // individualName 表示實(shí)體的標(biāo)識
    String sameIndividual = null; // 返回的等價(jià)實(shí)體結(jié)果
    String prefix = "prefix mymo: <" + Config.pizzaNs + ">\n" +
            "prefix rdfs: <" + RDFS.getURI() + ">\n" +
            "prefix owl: <" + OWL.getURI() + ">\n"; // 查詢前綴
    String QL = "SELECT ?等價(jià)實(shí)體 WHERE {?等價(jià)實(shí)體 owl:sameAs mymo:" + individualName + ".\n}"; // 查詢等價(jià)實(shí)體的 SPARQL 語句逞度,其中等價(jià)實(shí)體的關(guān)系可以用 owl:sameAs 表達(dá)
    String SPARQL = prefix + QL;  // 添加好前綴额划,構(gòu)建完整查詢語句
    // 使用 Jena API 構(gòu)建好查詢對象
    Query query = QueryFactory.create(SPARQL);
    QueryExecution qexec = QueryExecutionFactory.create(query, model);
    ResultSet results = qexec.execSelect();// 執(zhí)行查詢
    ResultSetRewindable resultSetRewindable = ResultSetFactory.makeRewindable(results);
    int numCols = resultSetRewindable.getResultVars().size();
    while (resultSetRewindable.hasNext()) { // 遍歷所有查詢結(jié)果
        QuerySolution querySolution = resultSetRewindable.next();
        for (int col = 0; col < numCols;col++) {
            String rVar = results.getResultVars().get(col);
            RDFNode obj = querySolution.get(rVar);
            sameIndividual = FmtUtils.stringForRDFNode(obj).split(":")[1];  // 獲取查詢結(jié)果-等價(jià)實(shí)體
        }
    }
    return sameIndividual;  // 返回查詢結(jié)果
}

除了 "查詢等價(jià)實(shí)體" 之外,還封裝了其它一些簡單操作档泽,例如查詢所有以 Subject 為主體的三元組:

/**
 * 查詢所有以 Subject 為主體的三元組(這里稱之為斷言)
 * 代碼還有待優(yōu)化
 */
@Override
public List<Statement> getStatementsBySubject(String subject) {
    List<Statement> statements = new ArrayList<Statement>();
    StmtIterator stmtIter = model.listStatements(); // 列出所有的三元組
    while(stmtIter.hasNext()) { // 循環(huán)所有斷言
        Statement statement = stmtIter.next();
        String subjectName = null;
        if (statement.getSubject() != null && statement.getSubject().getURI() != null) {
            String[] urlFields = statement.getSubject().getURI().split("#");
            if (urlFields.length > 1) {
                subjectName = urlFields[1];
            } else {
                subjectName =urlFields[0];
            }
            if (subjectName != null) {
                if (subjectName.equals(subject)) {  // 尋找主體為參數(shù) subject 的三元組
                    statements.add(statement);
                }
            }
          }
    }
    return statements;  // 返回最終結(jié)果
}

如上所述俊戳,本體查詢模塊就是對一些本體操作的封裝揖赴,是系統(tǒng)的數(shù)據(jù)訪問層。

到目前為止抑胎,本體查詢模塊封裝的都是一些非常簡單的操作燥滑,因此實(shí)際上是可以不單獨(dú)構(gòu)造一個(gè)模塊的。現(xiàn)在單獨(dú)劃分一個(gè)模塊阿逃,是為了方便之后的系統(tǒng)重構(gòu)铭拧,以后如果實(shí)現(xiàn)了本體的分布式存儲后者添加一些其它數(shù)據(jù)源如圖數(shù)據(jù)庫,那么只需要修改本體查詢模塊并可恃锉。

相關(guān)資料

SQARQL

Jena 官方關(guān)于 SQARQL 的教程

W3C SQARQL1.0 文檔

W3C SQARQL1.1 文檔

下一篇

下一篇開始將介紹語義理解模塊搀菩,語義理解模塊的主要作用是解析自然語言,使用查詢語義圖表達(dá)用戶的查詢語義破托,通過實(shí)體消歧肪跋、謂語消歧等操作提高語義理解的程度,最終通過本體查詢模塊查詢答案土砂。

汪.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末州既,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子萝映,更是在濱河造成了極大的恐慌吴叶,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锌俱,死亡現(xiàn)場離奇詭異晤郑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)贸宏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門造寝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吭练,你說我怎么就攤上這事诫龙。” “怎么了鲫咽?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵签赃,是天一觀的道長。 經(jīng)常有香客問我分尸,道長锦聊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任箩绍,我火速辦了婚禮孔庭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己圆到,他們只是感情好怎抛,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芽淡,像睡著了一般马绝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挣菲,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天富稻,我揣著相機(jī)與錄音,去河邊找鬼己单。 笑死唉窃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的纹笼。 我是一名探鬼主播纹份,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼廷痘!你這毒婦竟也來了蔓涧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤笋额,失蹤者是張志新(化名)和其女友劉穎元暴,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兄猩,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茉盏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了枢冤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸠姨。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖淹真,靈堂內(nèi)的尸體忽然破棺而出讶迁,到底是詐尸還是另有隱情,我是刑警寧澤核蘸,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布巍糯,位于F島的核電站,受9級特大地震影響客扎,放射性物質(zhì)發(fā)生泄漏祟峦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一徙鱼、第九天 我趴在偏房一處隱蔽的房頂上張望宅楞。 院中可真熱鬧,春花似錦、人聲如沸咱筛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迅箩。三九已至,卻和暖如春处铛,著一層夾襖步出監(jiān)牢的瞬間饲趋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工撤蟆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓恩脂,卻偏偏與公主長得像畸颅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子讨衣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361