国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

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

inapt / 490人閱讀

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

說(shuō)到“檔案”系統(tǒng),選文檔數(shù)據(jù)庫(kù)再合適不過(guò)了。談到文檔數(shù)據(jù)庫(kù)一般想到的是 MongoDB、CouchDB 之類(lèi)的,可這里要說(shuō)的不是這些,而是另一個(gè) NoSQL “文檔數(shù)據(jù)庫(kù)” —— Lucene。之所以要打引號(hào),是因?yàn)闀簳r(shí)還沒(méi)聽(tīng)到別人這樣說(shuō)。

需求

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

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

那這里說(shuō)的檔案是什么樣子呢?舉一個(gè)簡(jiǎn)單例子,一份個(gè)人簡(jiǎn)歷:

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

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

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

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

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

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

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

字段上可以有:

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

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

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

表單及驗(yàn)證

前面談到我自己有一個(gè)數(shù)據(jù)校驗(yàn)?zāi)K,對(duì)數(shù)據(jù)結(jié)構(gòu)的描述如下:

表單1
    字段1:類(lèi)型,是否必填,是否重復(fù),其他校驗(yàn)參數(shù)
    字段2……
枚舉1
    取值1:名稱(chēng)
    取值2……

舉一個(gè)栗子:

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

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

數(shù)據(jù)在校驗(yàn)成功后,會(huì)將數(shù)據(jù)清理為類(lèi)似以下 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)與此一致,對(duì)于使用 application/x-www-form-urlencoded 格式提交的數(shù)據(jù),可以根據(jù)"."、"["和"]"解析成上面的數(shù)據(jù)結(jié)構(gòu),就像 PHP 的請(qǐng)求參數(shù)解析方式。

存儲(chǔ)方式

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

我可不想這么費(fèi)勁。

為解決這些問(wèn)題,先梳理一下,Lucene 的基本字段類(lèi)型有:

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

還有其他的 IntField,FloatField…… 可以存數(shù)字的(關(guān)鍵的是可以按數(shù)字值大小來(lái)排序),ByteField 存二進(jìn)制數(shù)據(jù)等。還有,Lucene 支持一個(gè)字段存儲(chǔ)多個(gè)值,當(dāng)只需要一個(gè)值得時(shí)候拿一個(gè)就是了,需要多個(gè)就取多個(gè)值。

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

比較麻煩的是列表板塊。

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

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

如果還想完成需求:查詢(xún)某個(gè)日期范圍內(nèi)就讀某某學(xué)校的檔案,還是另行存儲(chǔ)吧。查詢(xún)時(shí)可以用外鍵關(guān)聯(lián),查出一個(gè)再 IN 去查另一個(gè)(注:Lucene沒(méi)有IN的操作,需要聯(lián)合使用MUST和SHOULD)。可以另外作為一個(gè)檔案存在當(dāng)前索引目錄內(nèi),更好的方式是獨(dú)立開(kāi)個(gè)附屬目錄存儲(chǔ),這樣做可以確保主數(shù)據(jù)更干凈。

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

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

查詢(xún)規(guī)則

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

{
    "id": "xxx",       // 等于
    "star": [1, 2],    // IN, Lucene 的 Must + Should
    "f1": {
        "-gt": 18,     // 大于
        "-le": 35      // 小于或等于
    },
    "f2": {
        "-ne": "zzz"   // 不等于
    },
    "f3": {
        "-or": "zzz"   // OR, 對(duì)應(yīng) Lucene 的 Should
    },
    "f4": {
        "-ni": [3, 4]  // NOT IN, 對(duì)應(yīng) Lucene 的 Must_Not
    },
    "f5": {
        "-ai": [1, 2]  // ALL IN, 對(duì)應(yīng) Lucene 的 Must
    },
    "f6": {
        "-oi": [5, 6]  // OR IN, 對(duì)應(yīng) 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)會(huì)以類(lèi)似 PHP 的請(qǐng)求參數(shù)解析方式解析類(lèi)似上面 JSON 的數(shù)據(jù)結(jié)構(gòu)。為了方便看和寫(xiě),也可支持將[]換成.,如:f6.-oi.=6 與 f6[-oi][]=6 是相同的。

熟悉 MongoDB 的人看這個(gè)會(huì)很眼熟,沒(méi)錯(cuò),這就是從 MongoDB 借鑒過(guò)來(lái),并用在我的關(guān)系數(shù)據(jù)庫(kù)查詢(xún)上。這里的 -or 和 -oi 是 Lucene 特有的,可以影響到排序,這對(duì)搜索那些可有可無(wú)的字段很有幫助。-ai 類(lèi)似于 Mongo 的 containsAll。

注:[2015/12/01] 以上"-"已換成"!"符號(hào)。

接口規(guī)范

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

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

后注

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

我在 github 上有個(gè)項(xiàng)目,不過(guò)還沒(méi)有搭建演示,日后有了再將鏈接添加到這里。

部分代碼:

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

參考資料:

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

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/64230.html

相關(guān)文章

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

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

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

    摘要:倒排索引是基于詞的搜索。關(guān)于倒排索引要學(xué)習(xí)搜索引擎,就需要了解倒排索引,要更加深刻地理解倒排索引,就要先了解什么是正排索引表。由于不是由記錄來(lái)確定屬性值,而是由屬性值來(lái)確定記錄的位置,因而稱(chēng)為倒排索引。 Lucene是什么? Lucene是apache軟件基金會(huì)4 jakarta項(xiàng)目組的一個(gè)子項(xiàng)目,是一個(gè)開(kāi)放源代碼的全文檢索引擎工具包,但它不是一個(gè)完整的全文檢索引擎,而是一個(gè)全文檢索引...

    wenshi11019 評(píng)論0 收藏0
  • Lucene解析 - 基本概念

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

    sunnyxd 評(píng)論0 收藏0
  • Lucene解析 - 基本概念

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

    appetizerio 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<