lucene 从0到1

Lucene[‘lusen] 是一个高性能的 java 全文检索工具包(引擎),现阶段 Apache 的顶级的开源项目,可基于它开发出各种全文搜索的应用。
一个全文检索系统需要做的可以分为两部分,第一部分是建立索引,第二部分是进行检索。下面就结合代码对这两部分进行讲解。

先创建一个由 maven 管理的 java 项目,在 pom 中添加 lucene 依赖

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-core</artifactId>
        <version>${lucene.version}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-queryparser</artifactId>
        <version>${lucene.version}</version>
    </dependency>
</dependencies>

然后

mvn clean install

把各种依赖导入

建立索引

建立索引是从原始文档到索引文件的过程,索引中包含索引和文档对象。每个文档对象有唯一的 id,文档对象里包含了很多 field,每个 field 有自己的名字(可重复)和相应的值。索引的最小单位是 Term,可以理解为分词之后的每个单词或者不进行分词的整体,也可以建立 n-gram 的 term。
常用的 Field 类如下:

Field 类 数据类型 是否分词 是否索引 是否存储 备注
StringField(FieldName, FieldValue,Store.YES)) String No Yes Yes or No 用于不进行分词的字符串,如订单号
LongField(FieldName, FieldValue,Store.YES) long Yes Yes Yes or No
StoredField(FieldName, FieldValue) 重载方法,支持多种类型 No No Yes 需要储存的文档信息,但不进行索引和分词
TextField(FieldName, FieldValue, Store.NO) String Yes Yes Yes or No 需要储存的正文内容
TextField(FieldName, reader) streamming Yes Yes No 因为是流,lucene猜测内容比较多,会采用Unstored

建立索引,第一步当然就是创建索引对象

Directory index = FSDirectory.open(Paths.get(indexPath));

因为有些内容需要分词,所以也需要建立文本分析器对象,并把它加入到索引 Writer 的配置中配置 IndexWriter,也对增量更新(IndexWriterConfig.OpenMode.APPEND、IndexWriterConfig.OpenMode.CREATE_OR_APPEND)还是全量更新(IndexWriterConfig.OpenMode.CREATE)进行设置:

Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig config = new IndexWriterConfig(analyzer);
config.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
IndexWriter writer = new IndexWriter(index, config);

下面就可以对索引进行写操作了,对于每个文档:

// 先创建一个文档(Document 对象)
Document doc = new Document();
// 解析原始文本并往文档中添加相应的 Field
Field pathField = new StringField("path", file.toString(), Field.Store.YES);
Field contentsField = new TextField("contents", buffer.toString(),Field.Store.YES);
doc.add(pathField);
doc.add(contentsField);
writer.addDocument(doc);

最后记得把该关的都关了

index.close();
writer.close();

建立后查看索引内内用

有一个开源项目可以查看索引文件,项目地址:https://github.com/DmitryKey/luke
克隆后进入文件夹“mvn install”,然后

java target/luke-swing-with-deps.jar

会弹出UI界面,选择索引所在文件夹,就可饮查看索引和进行一些简单的操作了。

进行查询

进行查询,首先要创建 IndexReader 对象来读取索引,并且把它交给 IndexSearcher 对象来进行搜索

IndexReader reader = DirectoryReader.open(FSDirectory.open(Paths.get(indexPath)));
IndexSearcher searcher = new IndexSearcher(reader);

对于输入的 String 类型的 query 我们需要对其解析成 IndexSearcher 可以查询的 query 类型

Analyzer analyzer = new StandardAnalyzer();
QueryParser parser = new QueryParser(field, analyzer);
Query query = parser.parse(raw_input);

进行搜索

TopDocs results = searcher.search(query, 10);// 搜索结果,包含了一些搜索的信息
ScoreDoc[] hits = results.scoreDocs;// 搜索所得结果的列表
int numTotalHits = Math.toIntExact(results.totalHits);//一共所得的结果
for (ScoreDoc hit : hits) {
    int docID = hit.doc;
    Document document = searcher.doc(docID);
    System.out.println("文档:" + document.get("path"));
    System.out.println(document.getField("contents").stringValue());
    System.out.println("相关度:" + hit.score);
    System.out.println("================================");
}

搜索常用的方法,评分应该是根据idf来算的

方法 说明
IndexSearcher.search(query, n) 根据 query 搜索评分最高的 n 条记录
IndexSearcher.search(query, filter, n) 添加过滤策略
IndexSearcher.search(query, n, sort) 添加排序策略
IndexSearcher.search(query, filter, n, sort) 添加过滤策略和排序策略

最后把该关的都关了

reader.close();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章