問題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 文檔
要索引的數據記錄、文檔在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(); } } }