成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

用 Lucene 構(gòu)建文檔數(shù)據(jù)庫

inapt / 503人閱讀

摘要:說到檔案系統(tǒng),選文檔數(shù)據(jù)庫再合適不過了。熟悉的人看這個會很眼熟,沒錯,這就是從借鑒過來,并用在我的關系數(shù)據(jù)庫查詢上。接口規(guī)范接口的主要目是為了傳遞數(shù)據(jù),數(shù)據(jù)結(jié)構(gòu)已經(jīng)在上面給出。為便于不同系統(tǒng)不同終端的數(shù)據(jù)交換,也將應當在接口支持之內(nèi)。

說到“檔案”系統(tǒng),選文檔數(shù)據(jù)庫再合適不過了。談到文檔數(shù)據(jù)庫一般想到的是 MongoDB、CouchDB 之類的,可這里要說的不是這些,而是另一個 NoSQL “文檔數(shù)據(jù)庫” —— Lucene。之所以要打引號,是因為暫時還沒聽到別人這樣說。

需求

最近公司要弄一個內(nèi)部搜索,對比各種方案后,決定用 Lucene。當做出第一個原型后,考慮到公司另外幾個項目將來也許用的上,而再寫一遍代碼可不是我的風格;又試用了開箱即用的 Solr,覺得那也不是我的菜。因為我項目內(nèi)已經(jīng)有類似 Solr 的 Schame 的配置在用了,我打算復用這個模塊;接口規(guī)范我也打算復用我現(xiàn)有的規(guī)范。

基礎的增刪改查比較簡單,很快就做出了原型。此時我想到公司另一個大模塊:檔案(或叫簡歷)。這部分我已計劃與另一個項目的類似模塊做整合,考慮用 MongoDB 重構(gòu)。既然 Lucene 可以存取較復雜的數(shù)據(jù)結(jié)構(gòu),何不借此機會研究一下用 Lucene 作為檔案系統(tǒng)的底層支撐呢。

那這里說的檔案是什么樣子呢?舉一個簡單例子,一份個人簡歷:

姓名:XXX
性別:男
照片:xxx/xxx.jpg
興趣愛好
    興趣:跑步、游泳、XX自定義
    簡介:是浪費時間的服務吉林省地方就,受到法律書籍地方
教育經(jīng)歷
    經(jīng)歷1
        日期區(qū)間: 2014/1/1~2015/1/1
        學校: Jiali.Dun
        專業(yè): 挖掘機
        學位:沒士
    經(jīng)歷2……

大概的文檔結(jié)構(gòu)就是就是這樣,字段、層級是不確定的,需要保持此結(jié)構(gòu),能存、能取,大部分字段可查詢、排序。

結(jié)構(gòu)化數(shù)據(jù)

總結(jié)以上檔案結(jié)構(gòu),組成上可分為:

a. 基礎板塊(名字,性別,照片)
b. 其他板塊(同上,但被區(qū)分開)
c. 列表板塊(教育經(jīng)歷)

上面特意將基礎信息稱為基礎“板塊”,也就是說,一般情況下一份檔案是由多個板塊組成的。也許您的檔案還會更復雜,比如興趣愛好下再分為運動、娛樂,這種劃分方式從存儲上來說與兩層設計沒什么區(qū)別,多了一個父級板塊的指向而已,但這增加了展現(xiàn)的復雜度?,F(xiàn)在大家都在談“扁平化”,我所理解的扁平不僅僅是把圖標拍扁了,更是信息獲取的渠道扁平了,能一下給我看的,不要讓我點一層菜單進去又點一層;能用標簽、搜索篩選的,不要讓我點目錄樹查找。

一個板塊就是一組鍵值對,此處我們將這一組規(guī)則稱為表單。那么,列表板塊就是由多個可重復表單組成的板塊。

字段上可以有:

a. 文本
b. 數(shù)字
c. 文件
d. 日期、時間(區(qū)間)
e. 單選、多選
f. 多條數(shù)據(jù)(文本、數(shù)字、日期等)

從 a~e 都是很常見的類型,文件可以轉(zhuǎn)儲到文件服務器上,這里只存 URL;日期、時間可以轉(zhuǎn)換成時間戳。而 f 是指這個字段的值可以輸入多個,通常用來記錄一些需要多條記錄東西,存儲上與多選一樣。

Lucene 原本就是一個字段可以存多個值,這太妙了。

表單及驗證

前面談到我自己有一個數(shù)據(jù)校驗模塊,對數(shù)據(jù)結(jié)構(gòu)的描述如下:

表單1
    字段1:類型,是否必填,是否重復,其他校驗參數(shù)
    字段2……
枚舉1
    取值1:名稱
    取值2……

舉一個栗子:

簡歷表單
    姓名:文本,必填,不重復,最大長度100
    性別:選項,必填,不重復,性別枚舉
    照片:圖片,選填,可重復,類型(jpg,png)
    興趣愛好:表單,選填,不重復,興趣愛好表單
    教育經(jīng)歷:表單,選填,可重復,教育經(jīng)歷表單
性別枚舉
    0:女
    1:男
    2:中性
興趣愛好表單
    興趣:文本,必填,可重復,最大長度50
    簡介:文本,選填,不重復,多行文本
教育經(jīng)歷表單
    日期區(qū)間:日期區(qū)間,必填,不重復
    學校:文本,必填,不重復
    專業(yè):文本,必填,不重復

此表單描述上也是為了方便編輯和解析,設計成了 表單->字段 兩層結(jié)構(gòu),未使用代碼嵌套而是使用鏈接嵌套的方式。校驗器在校驗的時候,發(fā)現(xiàn)字段類型為表單,取出對應表單遞歸下去就行了。那這么多表單都堆積在一起,怎么解決命名空間的問題呢?我設計為每個模塊(同一應用主題)一個這樣的配置,校驗器在處理表單時如果沒給出模塊名(配置名),則取當前模塊的指定名字的表單,有則取指定模塊下的表單。

數(shù)據(jù)在校驗成功后,會將數(shù)據(jù)清理為類似以下 JSON 的結(jié)構(gòu):

{
    "name": "XXX",
    "gender": 1,
    "photo": "upload/photo/xxxxxx.jpg",
    "hobby": {
        "interest": [
            "ljsdfsdfsd",
            "sldfj2ef"
        ],
        "comment": "sjldfjsldfsdlfjsldfsdfsdfsdfsdfsdf"
    },
    "education": [
        {
            "date": {
                "begin": Date(2014/1/1), 
                "end": Date(2015/1/1)
            },
            "university": "lwnfdsfwe",
            "professional": "slwef"
        }
    ]
}

輸入的數(shù)據(jù)結(jié)構(gòu)與此一致,對于使用 application/x-www-form-urlencoded 格式提交的數(shù)據(jù),可以根據(jù)"."、"["和"]"解析成上面的數(shù)據(jù)結(jié)構(gòu),就像 PHP 的請求參數(shù)解析方式。

存儲方式

OK,上面已經(jīng)扯了很多了,這開始進入正題了。數(shù)據(jù)都清理好了,可是這樣一個結(jié)構(gòu)的數(shù)據(jù)怎么存到 Lucene 檢索庫里呢?Lucene 可不是 MongoDB 能存儲 BSON 那樣的復雜結(jié)構(gòu)呀。難道像設計關系數(shù)據(jù)庫的 ERM 一樣,建幾個索引目錄當表使,然后用外鍵做關聯(lián),然后自己實現(xiàn)關聯(lián)查詢?;蛘?,把整個數(shù)據(jù)序列化扔到一個字段里,自己寫 Filter 、Query 來實現(xiàn)對復雜結(jié)構(gòu)的查詢?

我可不想這么費勁。

為解決這些問題,先梳理一下,Lucene 的基本字段類型有:

StringField: 基礎文本字段,可指定是否索引
StoredField: 僅存儲不索引(也就是不能搜索、查詢只能跟著文檔取出來看)
TextField  : 會在這上面應用分詞器,用來做全文檢索的

還有其他的 IntField,FloatField…… 可以存數(shù)字的(關鍵的是可以按數(shù)字值大小來排序),ByteField 存二進制數(shù)據(jù)等。還有,Lucene 支持一個字段存儲多個值,當只需要一個值得時候拿一個就是了,需要多個就取多個值。

現(xiàn)在,我可以假定默認的情況下基礎數(shù)據(jù)要能獨立索引以方便查詢的,他們用多帶帶的字段存放。其他數(shù)據(jù)可以在字段名上用一個分隔符連接板塊名和字段名。如果這些字段的字段名是不重復的(比如隨機生成的),直接用字段名即可。這樣做的好處是展現(xiàn)和存儲分離,當一個字段的數(shù)據(jù)從A板塊遷移到B板塊時,不用去修改過去已經(jīng)存儲的數(shù)據(jù),因為這個遷移僅僅是視覺上的遷移而已。目前我用 RDMS 實現(xiàn)的一套檔案系統(tǒng)就是這么干的。

比較麻煩的是列表板塊。

如果不需要對這部分的數(shù)據(jù)做查詢,那就直接序列化存起來。

如果需要對里面獨立的字段做搜索和排序,那就再序列化的基礎上,多加一個字段獨立存儲要索引的字段。比如添加字段 教育經(jīng)歷-學校,就可以對曾就讀過某個學校的檔案做搜索了。

如果還想完成需求:查詢某個日期范圍內(nèi)就讀某某學校的檔案,還是另行存儲吧。查詢時可以用外鍵關聯(lián),查出一個再 IN 去查另一個(注:Lucene沒有IN的操作,需要聯(lián)合使用MUST和SHOULD)??梢粤硗庾鳛橐粋€檔案存在當前索引目錄內(nèi),更好的方式是獨立開個附屬目錄存儲,這樣做可以確保主數(shù)據(jù)更干凈。

完整的存儲結(jié)構(gòu)為:

主要數(shù)據(jù)存儲
    記錄ID
    字段1:值1,值2……
    字段2……
列表數(shù)據(jù)存儲
    主記錄ID
    行記錄ID
    序號
    字段1:值1,值2……
    字段2……

查詢規(guī)則

我有一套已經(jīng)應用在 RDBMS 模型上的查詢規(guī)則,需要做的是將規(guī)則解析成 Lucene 的 Query。查詢規(guī)則如下:

{
    "id": "xxx",       // 等于
    "star": [1, 2],    // IN, Lucene 的 Must + Should
    "f1": {
        "-gt": 18,     // 大于
        "-le": 35      // 小于或等于
    },
    "f2": {
        "-ne": "zzz"   // 不等于
    },
    "f3": {
        "-or": "zzz"   // OR, 對應 Lucene 的 Should
    },
    "f4": {
        "-ni": [3, 4]  // NOT IN, 對應 Lucene 的 Must_Not
    },
    "f5": {
        "-ai": [1, 2]  // ALL IN, 對應 Lucene 的 Must
    },
    "f6": {
        "-oi": [5, 6]  // OR IN, 對應 Lucene 的 Should
    }
}

用 application/x-form-urlencode 可表示為:

id=xxx&star[]=1&star[]=2&f1[-gt]=18&f1[-le]=35&f6[-oi][]=5&f6[-oi][]=6

系統(tǒng)會以類似 PHP 的請求參數(shù)解析方式解析類似上面 JSON 的數(shù)據(jù)結(jié)構(gòu)。為了方便看和寫,也可支持將[]換成.,如:f6.-oi.=6 與 f6[-oi][]=6 是相同的。

熟悉 MongoDB 的人看這個會很眼熟,沒錯,這就是從 MongoDB 借鑒過來,并用在我的關系數(shù)據(jù)庫查詢上。這里的 -or 和 -oi 是 Lucene 特有的,可以影響到排序,這對搜索那些可有可無的字段很有幫助。-ai 類似于 Mongo 的 containsAll。

注:[2015/12/01] 以上"-"已換成"!"符號。

接口規(guī)范

接口的主要目是為了傳遞數(shù)據(jù),數(shù)據(jù)結(jié)構(gòu)已經(jīng)在上面給出。接口以 REST 風格給出,請求數(shù)據(jù)支持 application/x-form-urlencode,json,返回數(shù)據(jù)為 json。

如果你熟悉 Protobuf,也許意識到了上面的表單跟 proto 的描述很像,沒錯,這也是借鑒的。只是 Protobuf 沒法加更多的描述,所以我沒去用。這里的表單配置可以轉(zhuǎn)換為 proto 描述。為便于不同系統(tǒng)、不同終端的數(shù)據(jù)交換,protobuf 也將(應當)在接口支持之內(nèi)。

后注

如果不去考慮 Lucene 寫鎖的“問題”,我真心覺得這是個相當不錯的嵌入式文檔數(shù)據(jù)庫;雖然用 Lucene 存儲復雜結(jié)構(gòu)數(shù)據(jù)的可行性還有待商榷,但折騰一下對了解 Lucene 還是有價值的。不必強求必須用什么語言、框架或工具才能完成某件事,其實能辦成一件事的途徑有很多,多嘗試一下思路就更清晰一點。

我在 github 上有個項目,不過還沒有搭建演示,日后有了再將鏈接添加到這里。

部分代碼:

Lucene CRUD 封裝:https://github.com/ihongs/Hon...
表單校驗程序:https://github.com/ihongs/Hon...
表單配置規(guī)范:https://github.com/ihongs/Hon...

參考資料:

MongoDB 查詢:http://docs.mongodb.org/manua...
Lucene 查詢:https://lucene.apache.org/cor...
REST 簡介:http://baike.baidu.com/view/5...
PHP 請求參數(shù)解析(見第一條 Note):http://php.net/manual/zh/rese...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/64230.html

相關文章

  • Lucene 構(gòu)建文檔數(shù)據(jù)庫

    摘要:說到檔案系統(tǒng),選文檔數(shù)據(jù)庫再合適不過了。熟悉的人看這個會很眼熟,沒錯,這就是從借鑒過來,并用在我的關系數(shù)據(jù)庫查詢上。接口規(guī)范接口的主要目是為了傳遞數(shù)據(jù),數(shù)據(jù)結(jié)構(gòu)已經(jīng)在上面給出。為便于不同系統(tǒng)不同終端的數(shù)據(jù)交換,也將應當在接口支持之內(nèi)。 說到檔案系統(tǒng),選文檔數(shù)據(jù)庫再合適不過了。談到文檔數(shù)據(jù)庫一般想到的是 MongoDB、CouchDB 之類的,可這里要說的不是這些,而是另一個 NoSQL...

    zhangyucha0 評論0 收藏0
  • Lucene構(gòu)建個人搜索引擎解析

    摘要:倒排索引是基于詞的搜索。關于倒排索引要學習搜索引擎,就需要了解倒排索引,要更加深刻地理解倒排索引,就要先了解什么是正排索引表。由于不是由記錄來確定屬性值,而是由屬性值來確定記錄的位置,因而稱為倒排索引。 Lucene是什么? Lucene是apache軟件基金會4 jakarta項目組的一個子項目,是一個開放源代碼的全文檢索引擎工具包,但它不是一個完整的全文檢索引擎,而是一個全文檢索引...

    wenshi11019 評論0 收藏0
  • Lucene解析 - 基本概念

    摘要:基本概念在深入解讀之前,先了解下的幾個基本概念,以及這幾個概念背后隱藏的一些東西。如圖是一個內(nèi)的基本組成,內(nèi)數(shù)據(jù)只是一個抽象表示,不代表其內(nèi)部真實數(shù)據(jù)結(jié)構(gòu)。即詞典,是根據(jù)條件查找的基本索引。 前言 Apache Lucene是一個開源的高性能、可擴展的信息檢索引擎,提供了強大的數(shù)據(jù)檢索能力。Lucene已經(jīng)發(fā)展了很多年,其功能越來越強大,架構(gòu)也越來越精細。它目前不僅僅能支持全文索引,也...

    sunnyxd 評論0 收藏0
  • Lucene解析 - 基本概念

    摘要:基本概念在深入解讀之前,先了解下的幾個基本概念,以及這幾個概念背后隱藏的一些東西。如圖是一個內(nèi)的基本組成,內(nèi)數(shù)據(jù)只是一個抽象表示,不代表其內(nèi)部真實數(shù)據(jù)結(jié)構(gòu)。即詞典,是根據(jù)條件查找的基本索引。 前言 Apache Lucene是一個開源的高性能、可擴展的信息檢索引擎,提供了強大的數(shù)據(jù)檢索能力。Lucene已經(jīng)發(fā)展了很多年,其功能越來越強大,架構(gòu)也越來越精細。它目前不僅僅能支持全文索引,也...

    appetizerio 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<