Lucene 索引

Lucene索引

Lucene字段类型

文档是Lucene索引的基本单位,比文档更小的单位是字段,字段是文档的一部分。

每个字段由3部分组成:

  • 名称(name)
  • 类型(type)
  • 取值(value)

字段的取值一般分为文本类型(字符串、字符流等)二进制类型数值类型

字段类型
TestField TextField会把该字段的内容索引并词条化,但是不保存词向量。
StringFIeld StringField只会对该字段的内容索引,但是并不会词条化,也不保存词向量。
IntPoint IntPoint适合索引值为int类型的字段。
LongPoint LongPoint适合索引值为Long类型的字段。
FloatPoint FloatPoint适合索引值为float类型的字段。
DoublePoint DoublePoint适合索引值为double类型的字段。
SortedDocValuesField 存储值为文本内容的DocValue字段,SortedDocValuesFIeld适合索引字段值为文本内容,并需要按值进行排序的字段。
SortedSetDocValuesField 存储多值域的DocValue字段,SortedSetDocValuesField适合索引字段值为文本内容并且需要按值进行分组、聚合等操作的字段。
NumericDocValuesField 存储单个数值类型的DocValue字段,主要包括(int, long, float, double)
SortedNumericDocValuesField 存储数值类型的有序数组列表的DocValues字段。
StoredField StoredFIeld适合索引只需要保存字段值不进行其他操作的字段。

Lucene索引文档需要依靠一个 IndexWriter 对象,创建一个 IndexWriter 需要提供两个参数:

  • IndexWriterConfig 对象。

  • 索引的保存路径。

IndexWriterConfig 对象可以设置创建索引使用哪种分词器。

IndexWriter 对象的 addDocument() 方法用于添加文档,该方法的参数为 Document 对象。 IndexWriter 对象一次可以添加多个文档,最后调用 commit() 方法生成索引。

​ 文档是Lucene索引和搜索的基本单位,在代码中 Document 类标识文档,比文档更小的单位是域,也可以称为字段,一个文档可以有多个域。

FieldType 对象用于指定域的索引信息,例如是否解析、是否存储、是否保存词项频率、位移信息等。 FieldType 对象的 setIndexOptions() 方法可以设定域的索引选项。

索引 含义
IndexOptions.DOCS 只索引文档,词项频率和位移信息不保存。
IndexOptions.DOCS_AND_FREQS 只索引文档和词项频率。位移信息不保存。
IndexOptions.DOCS_AND_FREQS_AND_POSITIONS 索引文档、词项频率和位移信息
INdexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS 索引文档、词项频率、位移信息和偏移量。
INdexOptions.NONE 不索引

​ 全文搜索中很重要的一项需求是关键字高亮,要想准确地获取位置信息以及一些偏移量就需要在创建索引的时候进行记录。

​ 在索引的时候,可以使用 FieldType 对象提供的方法设置相对增量和位移信息。

相对增量和位移信息 含义
setStored(boolean value) 参数默认值为false,设置为true存储字段值。
setTokenized(boolean value) 参数设置为true,会使用配置的分词器对字段值进行词条化。
setStoreTermVectors(boolean value) 参数为true,保存词向量。
setStoreTermVectorPositions(boolean value) 参数为true,保存词项在词向量中的位移信息。
setStoreTermVectorOffsets(boolean value) 参数为true,保存词项在词向量中的偏移信息。

创建索引

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class CreateIndex {
    public static void main(String[] args) {
        News news1 = new News();
        news1.setId(1);
        news1.setTitle("习近平会见美国总统奥巴马,学习国外经验。");
        news1.setContent("国家主席习近平9月3日在杭州西湖国宾馆会见前来出席二十国集团领导人杭州峰会的美国总统奥巴马。。。");
        news1.setReply(672);

        News news2 = new News();
        news2.setId(2);
        news2.setTitle("中央经济工作会议定调 明年楼市三大信号");
        news2.setContent("每年年末的中央经济工作会议被外界视为未来一年中国宏观政策的“风向标”,在房地产领域,今年的中央经济工作会议做了这些表述:\n" +
                "\n" +
                "要构建房地产市场健康发展长效机制,坚持房子是用来住的、不是用来炒的定位,因城施策、分类指导,夯实城市政府主体责任,完善住房市场体系和住房保障体系。");
        news2.setReply(995);

        News news3 = new News();
        news3.setId(3);
        news3.setTitle("基于自编码器的表征学习:如何攻克半监督和无监督学习?");
        news3.setContent("为了将人工智能应用于从世界收集的大量无标注数据,一大关键难题是要能仅用少量监督或无监督的学习方法来学习有用的表征。尽管在数据上学习到的表征的有用性显然很大程度上取决于其所针对的最终任务,但仍可想见有些表征的性质可同时用于很多真实世界任务。在一篇有关表征学习的开创性论文中,Bengio et al. [1] 提出了这样一组元先验(meta-prior)。这些元先验来自对世界的一般性假设,比如解释性元素的层次化组织形式或解离性(disentanglement)、半监督学习的可能性、数据在低维流形上的汇集、可聚类性、时间和空间一致性。");
        news3.setReply(1872);

        Analyzer analyzer = new IKAnalyzer6x(true);
        IndexWriterConfig icw = new IndexWriterConfig(analyzer);
        icw.setOpenMode(OpenMode.CREATE_OR_APPEND);
        Directory dir = null;
        IndexWriter indexWriter = null;

        Path indexPath = Paths.get("indexdir");

        Date start = new Date();
        try{
            if(!Files.isReadable(indexPath)){
                System.out.println("Document directory " + indexPath.toAbsolutePath());
                System.exit(1);
            }

            dir = FSDirectory.open(indexPath);
            indexWriter = new IndexWriter(dir, icw);
            FieldType idType = new FieldType();
            idType.setIndexOptions(IndexOptions.DOCS);
            idType.setStored(true);

            FieldType titleType = new FieldType();
            titleType.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
            titleType.setStored(true);
            titleType.setTokenized(true);

            FieldType contentType = new FieldType();
            contentType.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
            contentType.setStored(true);
            contentType.setTokenized(true);
            contentType.setStoreTermVectors(true);
            contentType.setStoreTermVectorPositions(true);
            contentType.setStoreTermVectorOffsets(true);
            contentType.setStoreTermVectorPayloads(true);

            Document doc1 = new Document();
            doc1.add(new Field("id", String.valueOf(news1.getId()), idType));
            doc1.add(new Field("title", news1.getTitle(), titleType));
            doc1.add(new Field("content", news1.getContent(), contentType));
            doc1.add(new IntPoint("reply", news1.getReply()));
            doc1.add(new StoredField("reply_display", news1.getReply()));

            Document doc2 = new Document();
            doc2.add(new Field("id", String.valueOf(news2.getId()), idType));
            doc2.add(new Field("title", news2.getTitle(), titleType));
            doc2.add(new Field("content", news2.getContent(), contentType));
            doc2.add(new IntPoint("reply", news2.getReply()));
            doc2.add(new StoredField("reply_display", news2.getReply()));

            Document doc3 = new Document();
            doc3.add(new Field("id", String.valueOf(news3.getId()), idType));
            doc3.add(new Field("title", news3.getTitle(), titleType));
            doc3.add(new Field("content", news3.getContent(), contentType));
            doc3.add(new IntPoint("reply", news3.getReply()));
            doc3.add(new StoredField("reply_display", news3.getReply()));

            indexWriter.addDocument(doc1);
            indexWriter.addDocument(doc2);
            indexWriter.addDocument(doc3);
            indexWriter.commit();
            indexWriter.close();
            dir.close();

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

        Date end = new Date();
        System.out.println("索引用时:" + (end.getTime() - start.getTime()) + " milliseconds");


    }
}

删除索引

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class DeleteIndex {
    public static void main(String[] args) {
        deleteDoc("title", "学习");
    }
    public static void deleteDoc(String field, String key){
        Analyzer analyzer = new IKAnalyzer6x(true);
        IndexWriterConfig icw = new IndexWriterConfig();
        Path indexPath = Paths.get("indexdir");
        Directory directory;
        try{
            directory = FSDirectory.open(indexPath);
            IndexWriter indexWriter = new IndexWriter(directory, icw);
            long res = indexWriter.deleteDocuments(new Term(field, key));
            indexWriter.commit();
            indexWriter.close();
            System.out.println("删除成功!res:" + res);
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

索引更新

import java.nio.file.Path;
import java.nio.file.Paths;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class UpdateIndex {
    public static void main(String[] args) {
        Analyzer analyzer = new IKAnalyzer6x(true);
        IndexWriterConfig icw = new IndexWriterConfig(analyzer);
        Path indexPath = Paths.get("indexdir");
        Directory directory = null;
        try{
            directory = FSDirectory.open(indexPath);
            IndexWriter indexWriter = new IndexWriter(directory, icw);
            Document doc = new Document();
            doc.add(new TextField("id", "2", Store.YES));
            doc.add(new TextField("title", "北京大学开学迎4380名新生", Store.YES));
            doc.add(new TextField("content", "们中的大多数都对 Web 开发岗感兴趣,同时也对很多其它开发方向感兴趣。从下图可以看出,他们最想从事的开发方向依次是全栈网页开发、前端网页开发、后端网页开发、移动端开发、游戏开发、数据科学家等。", Store.YES));

            indexWriter.updateDocument(new Term("title", "北大"), doc);
            indexWriter.commit();
            indexWriter.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/top_wind_cloud/article/details/85855289