本來打算先寫寫analysis包,因為那個組件包是基礎。但寫着寫着就覺得沒有入口的說明,就跳到那一部分實在對不起自己和各位的理解。於是咱就先看看Document和Field,這兩個用於索引和查詢的數據結構。
我們大多數人用過數據庫,知道一個表里面的一行。如粗糙的下圖所示:
這個是關系型數據庫的典型存儲方式。我們在進行數據查詢的時候,也是提供字段值或者是模式等條件。那么lucene作為一個全文檢索的解決方案,從表面來看,也是類似於關系型數據庫方式。它為我們提供了
統一的數據索引接口(IndexWriter)和查詢接口(IndexSearcher)。在我們這次要說明的Document和Field,我們也可以對應理解成關系型數據庫的一個數據行和字段。於是再對應一下,可以將IndexWriter理解
成SQL里面的insert語句,而IndexSearcher對應成select語句。表面上就是這樣的,最多是使用方式不同。
有了這么一層考慮之后,再來理解Document和field,我想(嗯,是我想象的)應該比較容易了。
在《體系結構》的例子中,有如下代碼:
doc.add(new Field("fieldname", text, TextField.TYPE_STORED));
這表示啥意思,從上面的對比說明來看,就是在構造一行,往行里面添加列值(Field)。
Ok,我們有了點感覺之后再來看看org.apache.lucene.document包。
這里都是從lucene4.0里面拉出來的,跟3.x里面的一些用法有比較大的區別。(各位用3.x的同學,要注意api上的變化)
如果我們就是要建立針對學生成績表里面姓名和成績的全文檢索(這里應該考慮一下,到底什么是全文檢索?這里的全文是什么意思?所謂的“全”,到底是哪個范圍里面的“全”?這些都有助於各位同學建立有針對性的搜索系統,而不僅僅是把數據庫里面的查詢搬到lucene里面),那應該如何構造用於建立索引的Document數據?
構建一個Document:(So Easy!)
Document doc = new Document();
接下來,往Document中存放各個字段:
doc.add(new Field("name", text, TextField.TYPE_STORED));//這種方式還是從3.x一直用過來的
3.x里面的那個持久的Field構造函數:
Field(String name, String value, Field.Store store, Field.Index index, Field.TermVector termVector)
已經被棄用了。我第一次使用這個東西也被迷惑一小下。怎么要有這么多變量來說明這個字段的屬性。尤其是,加入一個屬性,我肯定是想要建立索引的(大部分情況下,針對文本內容來說)。
現在4.0里面推薦如下方式:
doc.add(new TextField("name", text, Store.YES));
由原來的Field分割成如下些個子類:
DoubleField, FloatField, IntField, LongField, StoredField, StringField, TextField ……
請特別注意上面的省略號,里面還有很多,跟特定類型對應Field子類。鑒於篇幅和勤快程度的考慮,我就不多列了。
有了以上幾個類,我們在add field時,應該更加明確了,就不會像以前只是籠統的區分Text和Number。
而且在新api里面,Field.Index枚舉類型被棄用了,其替代品是FieldType,這個類里有關於本字段數據處理的各種元數據,字段如下:
private boolean indexed;
private boolean stored;
private boolean tokenized = true;
private boolean storeTermVectors;
private boolean storeTermVectorOffsets;
private boolean storeTermVectorPositions;
private boolean storeTermVectorPayloads;
private boolean omitNorms;
…………
從這個重構方式里,我們也能看到lucene越來越成熟了,元數據划分歸類也更加細膩,而不是像以前那樣,讓新用戶來決定各種顯而易見的屬性。(請把這句話當成廢話,但是請考慮一下其重構原則)
言歸正傳,加完姓名的field之后,我們接着添加成績字段:
doc.add(new FloatField(“score”, 59.9F, Field.Store.YES);
通過這個構造函數(FloatField(String name, float value, Field.Store stored)),我們可以創建一個名叫score,值為59.9,且要保存到索引文件的FloatField。這里面也要特別說明一下。
請看這個構造函數的源碼:
public FloatField(String name, float value, Store stored) {
super(name, stored == Store.YES ? TYPE_STORED : TYPE_NOT_STORED);
fieldsData = Float.valueOf(value);
}
FloatField將Field.Store轉換成了TYPE_STORED : TYPE_NOT_STORED(顯而易見),這兩個對象都是FieldType實例。再來看看源碼(以TYPE_STORED為例):
static {
TYPE_STORED.setIndexed(true);
TYPE_STORED.setTokenized(true);
TYPE_STORED.setOmitNorms(true);
TYPE_STORED.setIndexOptions(IndexOptions.DOCS_ONLY);
TYPE_STORED.setNumericType(FieldType.NumericType.FLOAT);
TYPE_STORED.setStored(true);
TYPE_STORED.freeze();
}
這里要特別注意下,TYPE_STORED.setNumericType(FieldType.NumericType.FLOAT);這句說明我們可以在搜索時,針對score這個字段排序。
於是,我們也就要考慮一下,我們的字段類型的關聯問題,各位同樣可以跟數據庫表關聯起來理解。
文本類型(TextField):是一大塊需要經過分詞的文本;
字符串類型(StringField):是一個不需要分詞,而直接用於索引的字符串;
數字類型(LongField
, FloatField
, DoubleField
,IntField):首先是一個不變的屬性值,這類字段還有一個主要用途,就是可以用於對搜索的返回結果集排序或是按范圍查詢。
DocValues類型(類名中含有DocValues字樣的Field子類):這些個類可以理解成一個專門服務於Document,且可以用於排序,范圍查詢等方面的字段。
有了上面的說明,各位在使用時,尤其是在搜索時,對於字段是否可以排序,是否可按范圍查詢等問題,也就有答案了。
到這里,對document包的說明也應該是差不多了。但是數據庫里面還有date類型的字段,可惜lucene里面沒有對date的直接支持。但是各位都知道date可以變成long型的字段。這樣各位就可以針對時間進行存儲,排序,或是按范圍查詢了。
ok,這次就到這里,要接下去完成還是二二半吊子的analysis部分了。