搜索引擎(Lucene-索引詳解)

IndexWriter詳解

問題1:索引建立過程完成什麼事?java

回顧架構圖git

Lucene索引建立API 圖示github

Lucene索引建立代碼示例數據庫

public static void main(String[] args) throws IOException {
    // 建立使用的分詞器
    Analyzer analyzer = new IKAnalyzer4Lucene7(true);
    // 索引配置對象
    IndexWriterConfig config = new IndexWriterConfig( analyzer );
    // 設置索引庫的打開模式:新建、追加、新建或追加
    config.setOpenMode(OpenMode.CREATE_OR_APPEND);
    // 索引存放目錄
    // 存放到文件系統中
    Directory directory = FSDirectory.open((new File("f:/test/indextest")).toPath());
    // 存放到內存中
    // Directory directory = new RAMDirectory();
    // 建立索引寫對象
    IndexWriter writer = new IndexWriter(directory, config);
    // 建立document
    Document doc = new Document();
    // 往document中添加 商品id字段
    doc.add(new StoredField("prodId", "p0001"));
    // 往document中添加 商品名稱字段
    String name = "ThinkPad X1 Carbon 20KH0009CD/25CD 超極本輕薄筆記本電腦聯想";
    doc.add(new TextField("name", name, Store.YES));
}

IndexWriter涉及類圖示數組

IndexWriterConfig 寫索引配置:緩存

Ø 使用的分詞器。
Ø 如何打開索引(是新建,仍是追加)。
Ø 還可配置緩衝區大小、或緩存多少個文檔,再刷新到存儲中。
Ø 還可配置合併、刪除等的策略。安全

Directory 指定索引數據存放的位置:架構

Ø 內存
Ø 文件系統
Ø 數據庫ide

保 存 到 文 件 系 統 用 法 :
Directory directory = FSDirectory.open(Path path); // path 指 定 目工具

IndexWriter 用來創 創 建 、 維 護 一 個 索 引  。 它 的API 使 用 流 程

// 建立索引寫對象
IndexWriter writer = new IndexWriter(directory, config);
// 建立document
// 將文檔添加到索引
writer.addDocument(doc);
// 刪除文檔
//writer.deleteDocuments(terms);
//修改文檔
//writer.updateDocument(term, doc);
// 刷新
writer.flush();
// 提交
writer.commit()

注意:IndexWriter是線程安全的。若是你的業務代碼中有其餘的同步控制,請不要使用IndexWriter做爲鎖對象,以避免死鎖。

IndexWriter還提供:add方法、delete方法、updatre方法、其餘方法。

問題2: 索引庫中會存儲反向索引數據,會存儲document嗎?

問題3: document會以什麼結構存儲?

網頁會存儲哪些信息?

Document詳解

Document 文檔

要索引的數據記錄、文檔在lucene中的表示,是索引、搜索的基本單元。一個Document由多個字段Field構成。就像數據庫的記錄-字段。IndexWriter按加入的順序爲Document指定一個遞增的id(從0開始),稱爲文檔id。反向索引中存儲的是這個id,文檔存儲中正向索引也是這個id。業務數據的主鍵id只是文檔的一個字段。請查看Document的源碼,找出操做字段的API

Document API

Field

字段:由字段名name、字段值value(fieldsData)、字段類型 type 三部分構成。字段值能夠是文本(String、Reader 或 預分析的 TokenStream)、二
進制值(byte[])或數值。請查看Field的源碼,找出這三個屬性查看它提供了哪些構造方法供咱們使用。

IndexableField Field API

Document—Field 數據舉例

Ø 新 聞:新聞id,新聞標題、新聞內容、做者、所屬分類、發表時間
Ø 網 頁 搜 索 的 網 頁:標題、內容、連接地址
Ø 商 品: id、名稱、圖片連接、類別、價格、庫存、商家、品牌、月銷量、詳情…

問題1:咱們收集數據建立document對象來爲其建立索引,數據的全部屬性是否都須要加入到document中?如數據庫表中的數據記錄的全部字段是否都
須要放到document中?哪些字段應加入到document中?

問題2:是否是全部加入的字段都須要進行索引?是否是全部加入的字段都要保存到索引庫中?什麼樣的字段該被索引?什麼樣的字段該被存儲?

請就網頁、商品進行思考?

網頁:標題、內容、連接地址
商品: id、名稱、圖片連接、類別、價格、庫存、商家、品牌、月銷量、詳情…

問題3:各類要被索引的字段該以什麼樣的方式進行索引,全都是分詞進行索引,仍是有不一樣區別?

網頁:標題、內容、連接地址
商品: id、名稱、圖片連接、類別、價格、庫存、商家、品牌、月銷量、詳情…

從問題二、3得出:不一樣的字段會有不一樣的索引設置信息。這些信息經過字段的類型屬性type:IndexableFieldType對象來定義

IndexableFieldType

字段類型:描述該如何索引存儲該字
字段可選擇性地保存在索引中,這樣在搜索結果中,這些保存的字段值就可得到。一個Document應該包含一個或多個存儲字段來惟一標識一個文檔。爲何?注意:未存儲的字段,從索引中取得的document中是沒有這些字段的。

請查看IndexableFieldType 的源碼,找到存儲、分詞、索引信息的定義
請查看IndexableFieldType的實現類有哪些?

Document 類關係

IndexableFieldType API 說明

IndexOptions 索引選項說明:

Ø NONE
Not indexed 不索引
Ø DOCS
反向索引中只存儲了包含該詞的 文檔id,沒有詞頻、位置
Ø DOCS_AND_FREQS
反向索引中會存儲 文檔id、詞頻
Ø DOCS_AND_FREQS_AND_POSITIONS
反向索引中存儲 文檔id、詞頻、位置
Ø DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS
反向索引中存儲 文檔id、詞頻、位置、偏移量

public class IndexOptionsDemo {

	public static void main(String[] args) {
		// 建立使用的分詞器
		Analyzer analyzer = new IKAnalyzer4Lucene7(true);

		// 索引配置對象
		IndexWriterConfig config = new IndexWriterConfig(analyzer);

		try ( // 索引存放到文件系統中
				Directory directory = FSDirectory
						.open((new File("f:/test/indextest")).toPath());

				// 建立索引寫對象
				IndexWriter writer = new IndexWriter(directory, config);) {

			// 準備document
			Document doc = new Document();
			// 字段content
			String name = "content";
			String value = "張三說的確實在理";
			FieldType type = new FieldType();
			// 設置是否存儲該字段
			type.setStored(true); // 請試試不存儲的結果
			// 設置是否對該字段分詞
			type.setTokenized(true); // 請試試不分詞的結果
			// 設置該字段的索引選項
			type.setIndexOptions(
					IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS); // 請嘗試不一樣的選項的效果
			type.freeze(); // 使不可更改

			Field field = new Field(name, value, type);
			// 添加字段
			doc.add(field);
			// 加入到索引中
			writer.addDocument(doc);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

Luke 索引查看工具安裝

下載地址 : https://github.com/DmitryKey/luke/releases

當前最新版 7.2.0 可用於lucene7.3.0版

luke Document 查看說明:

問題4:若是要在搜索結果中作關鍵字高亮,須要什麼信息?若是要實現短語查詢、臨近查詢(跨度查詢),須要什麼信息?如 要搜索包含「張三」 「李四」,且兩詞之間跨度不超過5個字符 。

問題5:位置、偏移數據在反向索引中佔的存儲量佔比大不大?

問題6:若是某個字段不須要進行短語查詢、臨近查詢,那麼在反向索引中就不須要保存位置、偏移數據。這樣是否是能夠下降反向索引的數據量,提高效率?可是若是該字段要作高亮顯示支持,該怎麼辦?。

爲了提高反向索引的效率,這樣的字段的位置、偏移數據是不該該保存到反向索引中的。這也你前面看到 IndexOptions爲何有那些選項的緣由。在lucene4.0之前,反向索引中總會存儲這些數據,4.0後改進爲可選擇的。那對於只作高亮顯示(或獲得搜索結果後須要使用這些信息)的字段怎麼辦?

一個字段分詞器分詞後,每一個詞項會獲得一系列屬性信息,如 出現頻率、位置、偏移量等,這些信息構成一個詞項向量termVectors

請查看IndexableFieldType、FieldType中有沒有設置保存termVectors的方法。

IndexableFieldType API 說明

storeTermVectors

對於不須要在搜索反向索引時用到,但在搜索結果處理時須要的位置、偏移量、附加數據(payLoad) 的字段,咱們能夠單獨爲該字段存儲(文檔id詞項向量)的正向索引。

Ø boolean storeTermVectors() 是否存儲詞項向量
Ø boolean storeTermVectorPositions() 是否在詞項向量中存儲位置
Ø boolean storeTermVectorOffsets() 是否在詞項向量中存儲偏移量
Ø boolean storeTermVectorPayloads() 是否在詞項向量中存儲附加信息

FieldType實現類中有對應的set方法

ublic class IndexTermVectorsDemo {

	public static void main(String[] args) {
		// 建立使用的分詞器
		Analyzer analyzer = new IKAnalyzer4Lucene7(true);

		// 索引配置對象
		IndexWriterConfig config = new IndexWriterConfig(analyzer);

		try ( // 索引存放到文件系統中
				Directory directory = FSDirectory
						.open((new File("f:/test/indextest")).toPath());

				// 建立索引寫對象
				IndexWriter writer = new IndexWriter(directory, config);) {

			// 準備document
			Document doc = new Document();
			// 字段content
			String name = "content";
			String value = "張三說的確實在理";
			FieldType type = new FieldType();
			// 設置是否存儲該字段
			type.setStored(true); // 請試試不存儲的結果
			// 設置是否對該字段分詞
			type.setTokenized(true); // 請試試不分詞的結果
			// 設置該字段的索引選項
			type.setIndexOptions(IndexOptions.DOCS); // 反向索引中只保存詞項

			// 設置爲該字段保存詞項向量
			type.setStoreTermVectors(true);
			type.setStoreTermVectorPositions(true);
			type.setStoreTermVectorOffsets(true);
			type.setStoreTermVectorPayloads(true);

			type.freeze(); // 使不可更改

			Field field = new Field(name, value, type);
			// 添加字段
			doc.add(field);
			// 加入到索引中
			writer.addDocument(doc);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

概念說明:Token trem 詞條 。 分詞獲得的詞

什麼是附加信息Payloads

練習1

請爲商品記錄創建索引,字段信息以下:
Ø 商品id:字符串,不索引、但存儲
String prodId = "p0001";
Ø 商品名稱:字符串,分詞索引(存儲詞頻、位置、偏移量)、存儲
String name = 「ThinkPad X1 Carbon 20KH0009CD/25CD 超極本輕薄筆記本電腦";
Ø 圖片連接:僅存儲
String imgUrl = "http://www.dongnao.com/aaa";
Ø 商品簡介:字符串,分詞索引(不須要支持短語、臨近查詢)、存儲,結果中
支持高亮顯示
String simpleIntro = "集成顯卡 英特爾 酷睿 i5-8250U 14英寸";
Ø 品牌:字符串,不分詞索引,存儲
String brand = "ThinkPad";

問題7 :咱們每每須要對搜索的結果支持按不一樣的字段進行排序,如商品搜索結果按價格排序、按銷量排序等。以及對搜索結果進行按某字段分組統計,如
按品牌統計。假如咱們按關鍵字「娃娃」搜索後獲得相關的文檔id列表
{10,21,18,48,29,…..}
要對它們進行按價格排序有的人想看銷量排序
有時須要按品牌統計數量…
反向索引對排序有用嗎?需獲得每一個id對應的價格或銷售是多少、品牌是什麼,再進行排序、統計。這個價格、銷量、品牌數據在哪裏?若是搜到的文檔列表量很大,排序會有什麼問題沒?

空間換時間

對這種須要排序、分組、聚合的字段,爲其創建獨立的文檔->字段值的正向索引、列式存儲。這樣咱們要加載搜中文檔的這個字段的數據就快不少,耗內存少。

docValuesType

IndexableFieldType 中的 docValuesType方法 就是讓你來爲須要排序、分組、聚合的字段指定如何爲該字段建立文檔->字段值的正向索引的。

IndexableFieldType API 說明

DocValuesType 選項說明

Ø NONE 不開啓docvalue
Ø NUMERIC 單值、數值字段,用這個
Ø BINARY 單值、字節數組字段用
Ø SORTED 單值、字符字段用, 會預先對值字節進行排序、去重存儲
Ø SORTED_NUMERIC 單值、數值數組字段用,會預先對數值數組進行排序
Ø SORTED_SET 多值字段用,會預先對值字節進行排序、去重存儲

具體使用選擇 :

Ø 字符串+單值 會選擇SORTED做爲docvalue存儲
Ø 字符串+多值 會選擇SORTED_SET做爲docvalue存儲
Ø 數值或日期或枚舉字段+單值 會選擇NUMERIC 做爲docvalue存儲
Ø 數值或日期或枚舉字段+多值 會選擇SORTED_SET做爲docvalue存儲

強 調 : 需 要 排 序 、 分 組 、 聚 合 、 分 類 查 詢 ( 面 查 詢 ) 的 字 段 才 創 建docValues

練習2

Ø 一、修改品牌字段:支持統計查詢
Ø 二、增長商品類別字段:字符串(類別名),索引不分詞,不存儲、支持分類統計,多值(一個商品可能屬於多個類別)。
type = {「電腦」,」筆記本電腦」}
Ø 三、增長價格字段:整數,單位分,不索引、存儲,須要支持排序多 值 如 何 加 入 到document ?
同字段屢次加入

public class ProductIndexExercise1 {

	public static void main(String[] args) {
		// 建立使用的分詞器
		Analyzer analyzer = new IKAnalyzer4Lucene7(true);

		// 索引配置對象
		IndexWriterConfig config = new IndexWriterConfig(analyzer);

		try (
				// 索引存放目錄
				// 存放到文件系統中
				Directory directory = FSDirectory
						.open((new File("f:/test/indextest")).toPath());

				// 存放到內存中
				// Directory directory = new RAMDirectory();

				// 建立索引寫對象
				IndexWriter writer = new IndexWriter(directory, config);) {

			// 準備document
			Document doc = new Document();
			// 商品id:字符串,不索引、但存儲
			String prodId = "p0001";
			FieldType onlyStoredType = new FieldType();
			onlyStoredType.setTokenized(false);
			onlyStoredType.setIndexOptions(IndexOptions.NONE);
			onlyStoredType.setStored(true);
			onlyStoredType.freeze();
			doc.add(new Field("prodId", prodId, onlyStoredType));

			// 商品名稱:字符串,分詞索引(存儲詞頻、位置、偏移量)、存儲
			String name = "ThinkPad X1 Carbon 20KH0009CD/25CD 超極本輕薄筆記本電腦聯想";
			FieldType indexedAllStoredType = new FieldType();
			indexedAllStoredType.setStored(true);
			indexedAllStoredType.setTokenized(true);
			indexedAllStoredType.setIndexOptions(
					IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
			indexedAllStoredType.freeze();
			doc.add(new Field("name", name, indexedAllStoredType));

			// 圖片連接:僅存儲
			String imgUrl = "http://www.dongnao.com/aaa";
			doc.add(new Field("imgUrl", imgUrl, onlyStoredType));

			// 商品簡介:文本,分詞索引(不須要支持短語、臨近查詢)、存儲,結果中支持高亮顯示
			String simpleIntro = "集成顯卡 英特爾 酷睿 i5-8250U 14英寸";
			FieldType indexedTermVectorsStoredType = new FieldType();
			indexedTermVectorsStoredType.setStored(true);
			indexedTermVectorsStoredType.setTokenized(true);
			indexedTermVectorsStoredType
					.setIndexOptions(IndexOptions.DOCS_AND_FREQS);
			indexedTermVectorsStoredType.setStoreTermVectors(true);
			indexedTermVectorsStoredType.setStoreTermVectorPositions(true);
			indexedTermVectorsStoredType.setStoreTermVectorOffsets(true);
			indexedTermVectorsStoredType.freeze();

			doc.add(new Field("simpleIntro", simpleIntro,
					indexedTermVectorsStoredType));

			// 價格,整數,單位分,不索引、存儲
			int price = 2999900;
			// Field 類有整數類型值的構造方法嗎?
			// 用字節數組來存儲試試,仍是轉爲字符串?
			byte[] result = new byte[Integer.BYTES];
			NumericUtils.intToSortableBytes(price, result, 0);

			doc.add(new Field("price", result, onlyStoredType));

			// 執行後,請到luke中看下結果是什麼。

			// 用字節數組、字符串就背離了本義數值。

			// 請查看Field類中提供了對應的構造方法或其餘方法沒?
			// 請查看 IndexableField 類中對一個字段提供哪幾種數據類型值的讀取?
			// 請再查看Field類中對應的實現。
			// 結合Field的構造方法和numericValue()方法還有setIntValue()方法,你是否是很疑惑、迷糊了。

			// 搞不清楚爲何這樣,那就先來看看IndexWriter在索引、存儲字段時是如何使用這些方法的吧。

			writer.addDocument(doc);

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

如何加入數值字段

請查看Field類中提供了對應的構造方法或其餘方法沒?Field的構造方法和set方法:

構造方法沒有對應的,set方法卻是有,請看下setIntValue方法的源碼,看它是如何將字段值設爲一個整數值的,你有疑惑嗎? 再看下其餘的set方法。

請再查看IndexableField 的API :

回顧前面 Field 的定義

字段:由字段名name、字段值value、字段類型 type三部分構成。字段值能夠是文本(String 、Reader或預分析的TokenStream)、 二進制值(byte[])或數值

加入數值字段方式

Ø 擴展Field ,提供構造方法傳入數值類型值,賦給字段值字段;
Ø 改寫binaryValue() 方法,返回數值的字節引用。

public class MyIntField extends Field {
	public MyIntField(String fieldName, int value, FieldType type) {
		super(fieldName, type);
		this.fieldsData = Integer.valueOf(value);
	}

	@Override
	public BytesRef binaryValue() {
		byte[] bs = new byte[Integer.BYTES];
		NumericUtils.intToSortableBytes((Integer) this.fieldsData, bs, 0);
		return new BytesRef(bs);
	}
}

問題8: IndexableFieldType中最後定義的的pointDimensionCount(),pointNumBytes() 是作何用的?

Lucene6之後引入了點的概念來表示數值字段,廢除了原來的IntField等。在Point字段類中提供了精確、範圍查詢的便捷方法。
注意:只是引入點的概念,並未改變數值字段的本質。既然是點,就有空間概念:維度。一維:一個值,二維:兩個值的;……
pointDimensionCount() 返回點的維數
pointNumBytes() 返回點中數值類型的字節數。

Lucene預約義的字段子類,你可靈活選用

Ø TextField: Reader or String indexed for full-text search
Ø StringField: String indexed verbatim as a single token
Ø IntPoint: int indexed for exact/range queries.
Ø LongPoint: long indexed for exact/range queries.
Ø FloatPoint: float indexed for exact/range queries.
Ø DoublePoint: double indexed for exact/range queries.
Ø SortedDocValuesField: byte[] indexed column-wise for sorting/faceting
Ø SortedSetDocValuesField: SortedSet<byte[]> indexed column-wise for sorting/faceting
Ø NumericDocValuesField: long indexed column-wise for sorting/faceting
Ø SortedNumericDocValuesField: SortedSet<long> indexed column-wise for sorting/faceting
Ø StoredField: Stored-only value for retrieving in summary results

public class IndexWriteDemo {

	public static void main(String[] args) {
		// 建立使用的分詞器
		Analyzer analyzer = new IKAnalyzer4Lucene7(true);

		// 索引配置對象
		IndexWriterConfig config = new IndexWriterConfig(analyzer);

		try (
				// 索引存放目錄
				// 存放到文件系統中
				Directory directory = FSDirectory
						.open((new File("f:/test/indextest")).toPath());

				// 存放到內存中
				// Directory directory = new RAMDirectory();

				// 建立索引寫對象
				IndexWriter writer = new IndexWriter(directory, config);) {

			// 準備document
			Document doc = new Document();
			// 商品id:字符串,不索引、但存儲
			String prodId = "p0001";
			FieldType onlyStoredType = new FieldType();
			onlyStoredType.setTokenized(false);
			onlyStoredType.setIndexOptions(IndexOptions.NONE);
			onlyStoredType.setStored(true);
			onlyStoredType.freeze();
			doc.add(new Field("prodId", prodId, onlyStoredType));

			// 等同下一行
			// doc.add(new StoredField("prodId", prodId));

			// 商品名稱:字符串,分詞索引(存儲詞頻、位置、偏移量)、存儲
			String name = "ThinkPad X1 Carbon 20KH0009CD/25CD 超極本輕薄筆記本電腦聯想";
			// String name = "張三說的確實在理";
			// String name = "厲害了個人國,我終於等到你了";
			FieldType indexedAllStoredType = new FieldType();
			indexedAllStoredType.setStored(true);
			indexedAllStoredType.setTokenized(true);
			indexedAllStoredType.setIndexOptions(
					IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
			indexedAllStoredType.freeze();

			doc.add(new Field("name", name, indexedAllStoredType));

			// 圖片連接:僅存儲
			String imgUrl = "http://www.dongnao.com/aaa";
			doc.add(new Field("imgUrl", imgUrl, onlyStoredType));

			// 商品簡介:文本,分詞索引(不須要支持短語、臨近查詢)、存儲,結果中支持高亮顯示
			String simpleIntro = "集成顯卡 英特爾 酷睿 i5-8250U 14英寸";
			FieldType indexedTermVectorsStoredType = new FieldType();
			indexedTermVectorsStoredType.setStored(true);
			indexedTermVectorsStoredType.setTokenized(true);
			indexedTermVectorsStoredType
					.setIndexOptions(IndexOptions.DOCS_AND_FREQS);
			indexedTermVectorsStoredType.setStoreTermVectors(true);
			indexedTermVectorsStoredType.setStoreTermVectorPositions(true);
			indexedTermVectorsStoredType.setStoreTermVectorOffsets(true);
			indexedTermVectorsStoredType.freeze();

			doc.add(new Field("simpleIntro", simpleIntro,
					indexedTermVectorsStoredType));

			// 類別:字符串,索引不分詞,不存儲、支持分類統計,多值
			FieldType indexedDocValuesType = new FieldType();
			indexedDocValuesType.setTokenized(false);
			indexedDocValuesType.setIndexOptions(IndexOptions.DOCS);
			indexedDocValuesType.setDocValuesType(DocValuesType.SORTED_SET);
			indexedDocValuesType.freeze();

			doc.add(new Field("type", "電腦", indexedDocValuesType) {
				@Override
				public BytesRef binaryValue() {
					return new BytesRef((String) this.fieldsData);
				}
			});
			doc.add(new Field("type", "筆記本電腦", indexedDocValuesType) {
				@Override
				public BytesRef binaryValue() {
					return new BytesRef((String) this.fieldsData);
				}
			});

			// 等同下四行
			// doc.add(new StringField("type", "電腦", Store.NO));
			// doc.add(new SortedSetDocValuesField("type", new BytesRef("電腦")));
			// doc.add(new StringField("type", "筆記本電腦", Store.NO));
			// doc.add(new SortedSetDocValuesField("type", new
			// BytesRef("筆記本電腦")));

			// 價格,整數,單位分,不索引、存儲、要支持排序
			int price = 999900;
			FieldType numericDocValuesType = new FieldType();
			numericDocValuesType.setTokenized(false);
			numericDocValuesType.setIndexOptions(IndexOptions.DOCS);
			numericDocValuesType.setStored(true);
			numericDocValuesType.setDocValuesType(DocValuesType.NUMERIC);
			numericDocValuesType.setDimensions(1, Integer.BYTES);
			numericDocValuesType.freeze();

			doc.add(new MyIntField("price", price, numericDocValuesType));

			// 與下兩行等同
			// doc.add(new StoredField("price", price));
			// doc.add(new NumericDocValuesField("price", price));

			// 商家 索引(不分詞),存儲、按面(分類)查詢
			String fieldName = "shop";
			String value = "聯想官方旗艦店";
			doc.add(new StringField(fieldName, value, Store.YES));
			doc.add(new SortedDocValuesField(fieldName, new BytesRef(value)));

			// 上架時間:數值,排序須要
			long upShelfTime = System.currentTimeMillis();
			doc.add(new NumericDocValuesField("upShelfTime", upShelfTime));

			writer.addDocument(doc);

		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}

問題9: Field中提供那麼多的setXXValue()方法,是什麼意圖?
問題10: 加入索引時,每一個數據記錄須要都建立一個Document嗎?

索引更新

IndexWriter 索引更新 API

說明:

Ø Term 詞項 指定字段的詞項
Ø 刪除流程:根據Term、Query找到相關的文檔id、同時刪除索引信息,再根據文檔id刪除對應的文檔存儲。
Ø 更新流程:先刪除、再加入新的doc
Ø 注意:只可根據索引的字段進行更新。

public class IndexUpdateDemo {

	public static void main(String[] args) {
		// 建立使用的分詞器
		Analyzer analyzer = new IKAnalyzer4Lucene7(true);

		// 索引配置對象
		IndexWriterConfig config = new IndexWriterConfig(analyzer);

		try (
				// 索引存放目錄
				// 存放到文件系統中
				Directory directory = FSDirectory
						.open((new File("f:/test/indextest")).toPath());

				// 存放到內存中
				// Directory directory = new RAMDirectory();

				// 建立索引寫對象
				IndexWriter writer = new IndexWriter(directory, config);) {

			// Term term = new Term("prodId", "p0001");
			Term term = new Term("type", "筆記本電腦");

			// 準備document
			Document doc = new Document();
			// 商品id:字符串,不索引、但存儲
			String prodId = "p0003";
			FieldType onlyStoredType = new FieldType();
			onlyStoredType.setTokenized(false);
			onlyStoredType.setIndexOptions(IndexOptions.NONE);
			onlyStoredType.setStored(true);
			onlyStoredType.freeze();
			doc.add(new Field("prodId", prodId, onlyStoredType));

			writer.updateDocument(term, doc);

			// Term term = new Term("name", "筆記本電腦");
			// writer.deleteDocuments(term);

			writer.flush();

			writer.commit();
			System.out.println("執行更新完畢。");

		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}
相關文章
相關標籤/搜索