欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Lucene-2.2.0 源代碼閱讀學(xué)習(xí)(26)

系統(tǒng) 1691 0

如果在初始化一個(gè)IndexWriter索引器的時(shí)候,指定 useCompoundFile =false,則在指定的索引目錄中生成的索引文件就不是.cfs復(fù)合索引文件。

通過(guò)這種方式生成的索引文件,它的不同格式表明了它鎖存儲(chǔ)的關(guān)于索引的不同內(nèi)容。

至少,明確了在建立索引過(guò)程中,經(jīng)過(guò)加工處理的數(shù)據(jù)究竟去向如何,能夠加深對(duì)Lucene索引過(guò)程的理解。

通過(guò)在文章 Lucene-2.2.0 源代碼閱讀學(xué)習(xí)(4) 中的那個(gè)例子,可以運(yùn)行主函數(shù),觀察到索引目錄中生成了大量的不同擴(kuò)展名的索引文件,當(dāng)然它們不是復(fù)合索引文件,如圖所示:

Lucene-2.2.0 源代碼閱讀學(xué)習(xí)(26)

這些不同擴(kuò)展名的索引文件都是有一定的含義的。

如果只是根據(jù)這些文件名來(lái)說(shuō)明它的含義,讓人感覺(jué)很抽象,那么就通過(guò)代碼來(lái)看,它們到底都存儲(chǔ)了一些什么內(nèi)容。

_N.fnm文件

當(dāng)向一個(gè)IndexWriter索引器實(shí)例添加Document的時(shí)候,調(diào)用了IndexWroter的addDocument()方法,在方法的內(nèi)部調(diào)用如下:

buildSingleDocSegment() —> String segmentName = newRamSegmentName();

這時(shí),調(diào)用newRamSegmentName()方法生成了一個(gè)segment的名稱,形如_ram_N,這里N為36進(jìn)制數(shù)。

這個(gè)新生成的segmentName作為參數(shù)值傳遞到DocumentWriter類的addDocument()方法中:

dw.addDocument(segmentName, doc);

在DocumentWriter類中,這個(gè)segmentName依然是_ram_N形式的,再次作為參數(shù)值傳遞:

fieldInfos.write(directory, segment + ".fnm");

這個(gè)時(shí)候,就要發(fā)生變化了,在FieldInfos類的第一個(gè)write()方法中輸出System.out.println(name);,結(jié)果如下所示:

_ram_0.fnm
_ram_1.fnm
_ram_2.fnm
_ram_3.fnm
_ram_4.fnm
_ram_5.fnm
_ram_6.fnm
_ram_7.fnm
_ram_8.fnm
_ram_9.fnm
_0.fnm
_ram_a.fnm
_ram_b.fnm
_ram_c.fnm
_ram_d.fnm
_ram_e.fnm
_ram_f.fnm
_ram_g.fnm
_ram_h.fnm
_ram_i.fnm
_ram_j.fnm
_1.fnm
_ram_k.fnm

……

而且,可以從Directory看出究竟在這個(gè)過(guò)程中發(fā)生了怎樣的切換過(guò)程,在FieldInfos類的第一個(gè)write()方法中執(zhí)行:

??? if(d instanceof FSDirectory){
??? System.out.println("FSDirectory");
??? }
??? else{
??? System.out.println("----RAMDirectory");
??? }

輸出結(jié)果如下所示:

----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
FSDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
FSDirectory

……

可以看出,每次處理過(guò)10個(gè).fnm文件(文件全名_ram_N.fnm),是在RAMDirectory中,然后就切換到FSDirectory中,這時(shí)輸出到本地磁盤(pán)的索引目錄中的索引文件是_N.fnm,可以從上面的實(shí)例圖中看到_0.fnm、_1.fnm等等。

真正執(zhí)行向_N.fnm文件中寫(xiě)入內(nèi)容是在FieldInfos類的第二個(gè)write()方法中,可以從該方法的實(shí)現(xiàn)來(lái)看到底都寫(xiě)入了哪些內(nèi)容:

public void write(IndexOutput output) throws IOException {
??? output.writeVInt(size());
??? for (int i = 0; i < size(); i++) {
????? FieldInfo fi = fieldInfo(i);
????? byte bits = 0x0;
????? if (fi.isIndexed) bits |= IS_INDEXED;
????? if (fi.storeTermVector) bits |= STORE_TERMVECTOR;
????? if (fi.storePositionWithTermVector) bits |= STORE_POSITIONS_WITH_TERMVECTOR;
????? if (fi.storeOffsetWithTermVector) bits |= STORE_OFFSET_WITH_TERMVECTOR;
????? if (fi.omitNorms) bits |= OMIT_NORMS;
????? if (fi.storePayloads) bits |= STORE_PAYLOADS;
????? output.writeString(fi.name);
????? output.writeByte(bits);

??? }
}

從后兩行代碼可以看出,首先寫(xiě)入了一個(gè)Field的名稱(name),然后寫(xiě)入了一個(gè)byte值。這個(gè)byte的值可以根據(jù)從該FieldInfos類定義的一些標(biāo)志經(jīng)過(guò)位運(yùn)算得到,從而從FieldIno的實(shí)例中讀取Field的信息,根據(jù)Field的一些信息(如:是否被索引、是否存儲(chǔ)詞條向量等等)來(lái)設(shè)置byte bits,這些標(biāo)志的定義為:

static final byte IS_INDEXED = 0x1;
static final byte STORE_TERMVECTOR = 0x2;
static final byte STORE_POSITIONS_WITH_TERMVECTOR = 0x4;
static final byte STORE_OFFSET_WITH_TERMVECTOR = 0x8;
static final byte OMIT_NORMS = 0x10;
static final byte STORE_PAYLOADS = 0x20;

_N.fdt文件和_N.fdx文件

接著,在DocumentWriter類中的addDocumet()方法中,根據(jù)Directory實(shí)例、segment的名稱、一個(gè)FieldInfos的實(shí)例構(gòu)造了一個(gè)FieldsWriter類的實(shí)例:

FieldsWriter fieldsWriter =?? new FieldsWriter(directory, segment, fieldInfos);

可以從FieldsWriter類的構(gòu)造方法可以看出,實(shí)際上,根據(jù)生成的segment的名稱(_ram_N和_N)創(chuàng)建了兩個(gè)輸出流對(duì)象:

??? FieldsWriter(Directory d, String segment, FieldInfos fn) throws IOException {
??????? fieldInfos = fn;????????
??????? fieldsStream = d.createOutput(segment + ".fdt");
??????? indexStream = d.createOutput(segment + ".fdx");
??? }

這時(shí),_N.fdt和_N.fdx文件就要生成了。

繼續(xù)看DocumentWriter類中的addDocument()方法:

fieldsWriter.addDocument(doc);

這時(shí)進(jìn)入到FieldsWriter類中了,在addDocument()方法中提取Field的信息,寫(xiě)入到,_N.fdt和_N.fdx文件中。FieldsWriter類的addDocument()方法實(shí)現(xiàn)如下:

??? final void addDocument(Document doc) throws IOException {
??????? indexStream.writeLong(fieldsStream.getFilePointer()); ?? // 向indexStream中(即_N.fdx文件)中寫(xiě)入fieldsStream(_N.fdt文件)流中的當(dāng)前位置,也就是寫(xiě)入這個(gè)Field信息的位置

??????? int storedCount = 0;
??????? Iterator fieldIterator = doc.getFields().iterator();
??????? while (fieldIterator.hasNext()) {?? // 循環(huán)遍歷該Document中所有Field,統(tǒng)計(jì)需要存儲(chǔ)的Field的個(gè)數(shù)
??????????? Fieldable field = (Fieldable) fieldIterator.next();
??????????? if (field.isStored())
??????????????? storedCount++;
??????? }
?????? fieldsStream.writeVInt(storedCount); ?? // 存儲(chǔ)Document中需要存儲(chǔ)的的Field的個(gè)數(shù),寫(xiě)入到_N.fdt文件

??????? fieldIterator = doc.getFields().iterator();
??????? while (fieldIterator.hasNext()) {
??????????? Fieldable field = (Fieldable) fieldIterator.next();
??????????? // if the field as an instanceof FieldsReader.FieldForMerge, we're in merge mode
??????????? // and field.binaryValue() already returns the compressed value for a field
??????????? // with isCompressed()==true, so we disable compression in that case

??????????? boolean disableCompression = (field instanceof FieldsReader.FieldForMerge);
??????????? if (field.isStored()) {??? // 如果Field需要存儲(chǔ),將該Field的編號(hào)寫(xiě)入到_N.fdt文件
??????????????? fieldsStream.writeVInt(fieldInfos.fieldNumber(field.name()));

??????????????? byte bits = 0;
??????????????? if (field.isTokenized())
??????????????????? bits |= FieldsWriter.FIELD_IS_TOKENIZED;
??????????????? if (field.isBinary())
??????????????????? bits |= FieldsWriter.FIELD_IS_BINARY;
??????????????? if (field.isCompressed())
??????????????????? bits |= FieldsWriter.FIELD_IS_COMPRESSED;
???????????????
??????????????? fieldsStream.writeByte(bits); ?? // 將Field的是否分詞,或是否壓縮,或是否以二進(jìn)制流存儲(chǔ),這些信息都寫(xiě)入到_N.fdt文件
????????????????
??????????????? if (field.isCompressed()) {
????????????????? // 如果當(dāng)前Field可以被壓縮
????????????????? byte[] data = null;
?????????????????
????????????????? if (disableCompression) {
?????????????????????
// 已經(jīng)被壓縮過(guò),科恩那個(gè)需要進(jìn)行合并優(yōu)化
????????????????????? data = field.binaryValue();
????????????????? } else {
????????????????????? // 檢查Field是否以二進(jìn)制存儲(chǔ)
????????????????????? if (field.isBinary()) {
??????????????????????? data = compress(field.binaryValue());
????????????????????? }
????????????????????? else {???? //?? 設(shè)置編碼方式,壓縮存儲(chǔ)處理
??????????????????????? data = compress(field.stringValue().getBytes("UTF-8"));
????????????????????? }
????????????????? }
????????????????? final int len = data.length;
????????????????? fieldsStream.writeVInt(len); ??? // 寫(xiě)入Field名稱(以二進(jìn)制存儲(chǔ))的長(zhǎng)度到_N.fdt文件
????????????????? fieldsStream.writeBytes(data, len); // 通過(guò)字節(jié)流的方式,寫(xiě)入Field名稱(以二進(jìn)制存儲(chǔ))到_N.fdt文件
??????????????? }
??????????????? else {
?????????????????
// 如果當(dāng)前這個(gè)Field不能進(jìn)行壓縮
????????????????? if (field.isBinary()) {
??????????????????? byte[] data = field.binaryValue();
??????????????????? final int len = data.length;
???????????????????
fieldsStream.writeVInt(len);
??????????????????? fieldsStream.writeBytes(data, len);
????????????????? }
????????????????? else {
??????????????????? fieldsStream.writeString(field.stringValue()); ??? // 如果Field不是以二進(jìn)制存儲(chǔ),則以String的格式寫(xiě)入到_N.fdt文件
????????????????? }
??????????????? }
??????????? }
??????? }
??? }

從該方法可以看出:

_N.fdx文件(即indexStream流)中寫(xiě)入的內(nèi)容是:一個(gè)Field在_N.fdt文件中位置。

_N.fdt文件(即fieldsStream流)中寫(xiě)入的內(nèi)容是:

(1) Document中需要存儲(chǔ)的Field的數(shù)量;

(2) 每個(gè)Field在Document中的編號(hào);

(3) 每個(gè)Field關(guān)于是否分詞、是否壓縮、是否以二進(jìn)制存儲(chǔ)這三個(gè)指標(biāo)的一個(gè)組合值;

(4) 每個(gè)Field的長(zhǎng)度;

(5) 每個(gè)Field的內(nèi)容(binaryValue或stringValue);

_N.frq文件和_N.prx文件

仍然在DocumentWriter類的addDocument()方法中看:

writePostings(postings, segment);

因?yàn)樵谡{(diào)用該方法之前,已經(jīng)對(duì)Documeng進(jìn)行了倒排,在倒排的過(guò)程中對(duì)Document中的Field進(jìn)行了處理,如果Field指定了要進(jìn)行分詞,則在倒排的時(shí)候進(jìn)行了分詞處理,這時(shí)生成了詞條。然后調(diào)用writePostings()方法,根據(jù)生成的segment的名稱_ram_N,設(shè)置詞條的頻率、位置等信息,并寫(xiě)入到索引目錄中。

在writePostings()方法中,首先創(chuàng)建了兩個(gè)輸出流:

????? freq = directory.createOutput(segment + ".frq");
????? prox = directory.createOutput(segment + ".prx");

這時(shí),_N.frq文件和_N.prx文件就要在索引目錄中生成了。

經(jīng)過(guò)倒排,各個(gè)詞條的重要信息都被存儲(chǔ)到了Posting對(duì)象中,Posting類是為詞條的信息服務(wù)的。因此,在writePostings()方法中可以遍歷Posting[]數(shù)組中的各個(gè)Posting實(shí)例,讀取并處理這些信息,然后輸出到索引目錄中。

設(shè)置_N.frq文件的起始寫(xiě)入內(nèi)容:

??????? int postingFreq = posting.freq;
??????? if (postingFreq == 1)?????
// 如果該詞條第一次出現(xiàn)造Document中
????????? freq.writeVInt(1);????
// 頻率色繪制為1
??????? else {
????????? freq.writeVInt(0);???? // 如果不是第一次出現(xiàn),對(duì)應(yīng)的Document的編號(hào)0要寫(xiě)入到_N.frq文件
????????? freq.writeVInt(postingFreq);???? // 設(shè)置一個(gè)詞條在該Document中的頻率值
??????? }

再看prox輸出流:

??????????? if (payloadLength == lastPayloadLength) {???? // 其中,int lastPayloadLength = -1;
?????????????
// the length of the current payload equals the length
??????????? // of the previous one. So we do not have to store the length
??????????? // again and we only shift the position delta by one bit

????????????? prox.writeVInt(delta * 2); ??? //其中,int delta = position - lastPosition,int position = positions[j];
??????????? } else {
???????????
// the length of the current payload is different from the
??????????? // previous one. We shift the position delta, set the lowest
??????????? // bit and store the current payload length as VInt.

????????????
prox.writeVInt(delta * 2 + 1);
????????????? prox.writeVInt(payloadLength);
????????????? lastPayloadLength = payloadLength;
??????????? }
??????????? if (payloadLength > 0) {
??????????? // write current payload
?????????????
prox.writeBytes(payload.data, payload.offset, payload.length);
??????????? }
????????? } else {
?????????
// field does not store payloads, just write position delta as VInt
???????????
prox.writeVInt(delta);
????????? }

一個(gè)Posting包含了關(guān)于一個(gè)詞條在一個(gè)Document中出現(xiàn)的所有位置(用一個(gè)int[]數(shù)組來(lái)描述)、頻率(int)、該詞條對(duì)應(yīng)的所有的Payload信息(用Payload[]來(lái)描述,因?yàn)橐粋€(gè)詞條具有了頻率信息,自然就對(duì)應(yīng)了多個(gè)Payload)。

關(guān)于Payload可以參考文章 Lucene-2.2.0 源代碼閱讀學(xué)習(xí)(23)

_N.prx文件文件寫(xiě)入的內(nèi)容都是與位置相關(guān)的數(shù)據(jù)。

從上面可以看出:

_N.frq文件(即freq流)中寫(xiě)入的內(nèi)容是:

(1) 一個(gè)詞條所在的Document的編號(hào);

(2) 每個(gè)詞條在Document中頻率(即:出現(xiàn)的次數(shù));

_N.prx文件(即prox流)中寫(xiě)入的內(nèi)容是:

其實(shí)主要就是Payload的信息,如:一個(gè)詞條對(duì)應(yīng)的Payload的長(zhǎng)度信息、起始偏移量信息;

_N.nrm文件

在DocumentWriter類的addDocument()方法中可以看到調(diào)用了writeNorms()方法:

writeNorms(segment);

也是根據(jù)生成的segment的名稱_ram_N來(lái)創(chuàng)建一個(gè)輸出流,看writeNorms()方法的定義:

private final void writeNorms(String segment) throws IOException {
??? for(int n = 0; n < fieldInfos.size(); n++){
????? FieldInfo fi = fieldInfos.fieldInfo(n);
????? if(fi.isIndexed && !fi.omitNorms){
??????? float norm = fieldBoosts[n] * similarity.lengthNorm(fi.name, fieldLengths[n]);
??????? IndexOutput norms = directory.createOutput(segment + ".f" + n);
??????? try {
????????? norms.writeByte(Similarity.encodeNorm(norm));
??????? } finally {
????????? norms.close();
??????? }
????? }
??? }
}

將一些標(biāo)準(zhǔn)化因子的信息,都寫(xiě)入到了_N.nrm文件。其中每個(gè)segment對(duì)應(yīng)著一個(gè)_N.nrm文件。

關(guān)于標(biāo)準(zhǔn)化因子可以參考文章 Lucene-2.2.0 源代碼閱讀學(xué)習(xí)(19) ,或者直接參考Apache官方網(wǎng)站 http://lucene.apache.org/java/docs/fileformats.html#Normalization%20Factors

關(guān)于不同格式的索引文件的內(nèi)容示例

為了直觀,寫(xiě)一個(gè)簡(jiǎn)單的例子:

package org.shirdrn.lucene;

import java.io.IOException;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.LockObtainFailedException;

public class LuceneIndexFormat {
public static void main(String[] args) {
?? String indexPath = "E:\\Lucene\\myindex";
?? String maven = "Maven is a software project management and comprehension tool.";
?? String lucene = "Apache Lucene is a search engine written entirely in Java.";
?? Document doc1 = new Document();
?? doc1.add(new Field("maven",maven,Field.Store.YES,Field.Index.TOKENIZED));
?? Document doc2 = new Document();
?? doc2.add(new Field("lucene",lucene,Field.Store.YES,Field.Index.TOKENIZED));
?? try {
??? IndexWriter indexWriter = new IndexWriter(indexPath,new StandardAnalyzer(),true);
??? indexWriter.setUseCompoundFile(false);
??? indexWriter.addDocument(doc1);
??? indexWriter.addDocument(doc2);
??? indexWriter.close();
?? } catch (CorruptIndexException e) {
??? e.printStackTrace();
?? } catch (LockObtainFailedException e) {
??? e.printStackTrace();
?? } catch (IOException e) {
??? e.printStackTrace();
?? }
}
}

運(yùn)行主函數(shù)后,在指定的索引目錄下生成了索引文件,而且是同一個(gè)索引段,如圖所示:

使用UltraEdit-32打開(kāi)_0.fnm文件,可以看到內(nèi)容如下所示:

就是我們?cè)诔绦蛑性O(shè)置的,即:

?? doc.add(new Field("maven",maven,Field.Store.YES,Field.Index.TOKENIZED));
?? doc.add(new Field("lucene",lucene,Field.Store.YES,Field.Index.TOKENIZED));

就是這兩個(gè)Field的name。

使用UltraEdit-32打開(kāi)_0.fdt文件,可以看到內(nèi)容如下所示:

其實(shí),就是Field的內(nèi)容。(上面的文本內(nèi)容實(shí)際上存儲(chǔ)在一行)

使用UltraEdit-32打開(kāi)_0.fdx文件,可以看到內(nèi)容如下所示:

其實(shí),就是在_0.fdt文件中,兩個(gè)Field的存放位置。

第一個(gè)Field是從0位置開(kāi)始的,第二個(gè)是從42(這里是16進(jìn)制,十進(jìn)制為66)位置開(kāi)始的。

使用UltraEdit-32打開(kāi)_0.nrm文件,可以看到內(nèi)容如下所示:

這里是標(biāo)準(zhǔn)化因子信息。

(關(guān)于標(biāo)準(zhǔn)化因子可以參考文章 Lucene-2.2.0 源代碼閱讀學(xué)習(xí)(19) ,或者直接參考Apache官方網(wǎng)站 http://lucene.apache.org/java/docs/fileformats.html#Normalization%20Factors 。)

?

Lucene-2.2.0 源代碼閱讀學(xué)習(xí)(26)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 久久99精品视频 | 一级毛片视频在线 | 日本在线观看视频网站 | 精品一区二区三区在线观看l | 84pao视频强力打造免费视频 | 久草久草在线 | 国产第一页浮力 | 日本一级淫片免费看 | 九九九九精品视频在线播放 | 日本午夜看x费免 | 欧美乱强性伦xxxxx | 成人免费无毒在线观看网站 | 亚洲国产天堂久久精品网 | 91 在线 | 成人片网址 | 日韩欧美在线一区二区三区 | 日韩精品一区二区三区 | 国产成人高清 | 午夜日韩 | 天堂在线免费视频 | 国产香蕉视频在线 | 高清视频在线播放 | 在线视频h| 李旭个人资料及简介 | 久草在线观看首页 | 国产婷婷色综合AV蜜臀AV | 久久久久亚洲精品 | 久久香蕉网| 久久特级毛片 | 日韩高清免费在线观看 | 亲爱的热爱的电视剧免费观看 | 久久精品视频免费观看 | 国产色在线| 国产日韩一区二区三区 | 99国产精品| 亚洲精品在线播放 | 中文精品久久 | 国产精品午夜电影 | av国语| 欧洲精品在线观看 | 成a人v在线观看视频 |