Lucene 简明教程
Lucene - Overview
Lucene 是一个简单但强大的基于 Java 的 Search 库。它可以在任何应用程序中使用,以向其添加搜索功能。Lucene 是一个开源项目。它具有可伸缩性。这个高性能库用于索引和搜索几乎任何类型的文本。Lucene 库提供了任何搜索应用程序所需的核心的操作。索引和搜索。
How Search Application works?
搜索应用程序执行以下部分或全部操作 -
Step |
Title |
Description |
1 |
Acquire Raw Content |
任何搜索应用程序的第一步是收集要进行搜索应用程序的目标内容。 |
2 |
Build the document |
下一步是从原始内容中构建搜索应用程序可以轻松理解和解释的文档。 |
3 |
Analyze the document |
在索引过程开始之前,要分析文档,确定哪些部分的文本是索引的候选项。此过程就是文档分析过程。 |
4 |
Indexing the document |
一旦构建并分析了文档,下一步就是对其进行索引,以便可以根据某些键检索该文档,而不是整个文档的内容。索引过程类似于书末的索引,其中常用词显示其页码,以便可以快速跟踪这些词,而不是搜索整本书。 |
5 |
User Interface for Search |
一旦索引数据库准备就绪,应用程序就可以进行任何搜索。为了便于用户进行搜索,该应用程序必须提供一个用户 a mean 或 a user interface ,用户可以在其中输入文本并开始搜索过程。 |
6 |
Build Query |
一旦用户发出搜索文本的请求,应用程序应使用该文本准备一个查询对象,该文本可用于查询索引数据库以获取相关详细信息。 |
7 |
Search Query |
使用查询对象,然后检查索引数据库以获取相关详细信息和内容文档。 |
8 |
Render Results |
收到结果后,应用程序应决定如何使用用户界面向用户显示结果。第一步要显示多少信息,依此类推。 |
除了这些基本操作外,搜索应用程序还可以提供 administration user interface 并帮助应用程序的管理员根据用户配置文件控制搜索级别。搜索结果分析是任何搜索应用程序的另一个重要且高级的方面。
Lucene - Environment Setup
本教程将指导你如何准备一个开发环境来使用 Spring 框架开始你的工作。本教程还将教你如何在你的机器上设置 JDK、Tomcat 和 Eclipse,然后设置 Spring 框架 -
Step 1 - Java Development Kit (JDK) Setup
你可以从 Oracle 的 Java 网站下载 SDK 的最新版本: Java SE Downloads 。你将在下载的文件中找到用于安装 JDK 的说明;按照给定的说明安装和配置设置。最后设置 PATH 和 JAVA_HOME 环境变量以引用包含 Java 和 javac 的目录,通常分别为 java_install_dir/bin 和 java_install_dir。
如果你正在运行 Windows,并在 C:\jdk1.6.0_15 中安装了 JDK,则你必须在你 C:\autoexec.bat 文件中放入以下行。
set PATH = C:\jdk1.6.0_15\bin;%PATH%
set JAVA_HOME = C:\jdk1.6.0_15
或者,在 Windows NT/2000/XP 中,您还可以右键单击 My Computer ,选择 Properties ,然后 Advanced ,再选择 Environment Variables 。然后,可以更新 PATH 值并按 OK 按钮。
在 Unix(Solaris、Linux 等)中,如果 SDK 安装在 /usr/local/jdk1.6.0_15 中,且您使用 C shell,则可以将以下内容放在 .cshrc 文件中。
setenv PATH /usr/local/jdk1.6.0_15/bin:$PATH
setenv JAVA_HOME /usr/local/jdk1.6.0_15
或者,如果您使用 Borland JBuilder、Eclipse、IntelliJ IDEA 或 Sun ONE Studio 等这样的 Integrated Development Environment (IDE) ,则编译并运行一个简单程序以确认 IDE 知道您安装 Java 的位置,否则可按照 IDE 文档中的给定内容进行适当的设置。
Step 2 - Eclipse IDE Setup
本教程中的所有示例均使用 Eclipse IDE 编写。因此,我建议您应在计算机上安装最新版本的 Eclipse。
要安装 Eclipse IDE,请从 https://www.eclipse.org/downloads/ 下载最新的 Eclipse 二进制文件。下载完安装程序后,将二进制发行版解压缩到方便的位置。例如,在 C:\eclipse on windows, 或 /usr/local/eclipse on Linux/Unix 中,最后适当设置 PATH 变量。
可以通过在 Windows 计算机上执行以下命令启动 Eclipse,或者您可以简单地双击 eclipse.exe
%C:\eclipse\eclipse.exe
可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令启动 Eclipse −
$/usr/local/eclipse/eclipse
成功启动后,应显示以下结果 −
Step 3 - Setup Lucene Framework Libraries
如果启动成功,则可以继续设置 Lucene 框架。以下是在计算机上下载并安装框架的简单步骤。
-
选择是要在 Windows 还是 Unix 中安装 Lucene,然后继续执行下一步,下载 Windows 的 .zip 文件和 Unix 的 .tz 文件。
-
从 https://archive.apache.org/dist/lucene/java/ 下载适合版本的 Lucene 框架二进制文件。
-
撰写本教程时,已在 Windows 计算机上下载了 lucene-3.6.2.zip,且解压缩下载的文件后,将如下所示,在 C:\lucene-3.6.2 中提供目录结构。
您将在目录 C:\lucene-3.6.2 中找到所有 Lucene 库。确保正确在此目录上设置您的 CLASSPATH 变量,否则在运行应用程序时将面临问题。如果使用 Eclipse,则无需设置 CLASSPATH,因为所有设置均将通过 Eclipse 完成。
完成此最后一步后,即可继续在下一章中看到的第一个 Lucene 示例。
Lucene - First Application
在本章中,我们将学习使用 Lucene Framework 进行实际编程。在开始使用 Lucene 框架编写第一个示例之前,您必须确保已正确设置 Lucene 环境,如 Lucene - Environment Setup 教程中所述。建议您具备 Eclipse IDE 的工作知识。
现在让我们继续编写一个简单的搜索应用程序,该应用程序将打印找到的搜索结果数。我们还将看到在此过程中创建的索引列表。
Step 1 - Create Java Project
第一步是使用 Eclipse IDE 创建一个简单的 Java 项目。按选项 File > New → Project ,最后从向导列表中选择 Java Project 向导。现在,使用向导窗口如下所示,将项目命名为 LuceneFirstApplication −
成功创建项目后,您的 Project Explorer 中将包含以下内容 −
Step 2 - Add Required Libraries
现在让我们在项目中添加 Lucene 核心框架库。若要执行此操作,请右键单击项目名称 LuceneFirstApplication ,然后按上下文菜单中提供的以下选项: Build Path → Configure Build Path ,以如下显示 Java 构建路径窗口 −
现在,使用 Libraries 下的 Add External JARs 按钮从 Lucene 安装目录添加以下核心 JAR。
-
lucene-core-3.6.2
Step 3 - Create Source Files
让我们在 LuceneFirstApplication 项目下创建实际的源文件。首先我们需要创建一个名为 com.tutorialspoint.lucene. 的包。为此,右键单击程序包资源管理器部分中的 src 并选择以下选项: New → Package 。
接下来,我们将在 com.tutorialspoint.lucene 包下创建 LuceneTester.java 和其他 java 类。
LuceneConstants.java
此类用于提供将在整个示例应用程序中使用的各种常量。
package com.tutorialspoint.lucene;
public class LuceneConstants {
public static final String CONTENTS = "contents";
public static final String FILE_NAME = "filename";
public static final String FILE_PATH = "filepath";
public static final int MAX_SEARCH = 10;
}
TextFileFilter.java
此类用作 .txt file 过滤器。
package com.tutorialspoint.lucene;
import java.io.File;
import java.io.FileFilter;
public class TextFileFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
return pathname.getName().toLowerCase().endsWith(".txt");
}
}
Indexer.java
此类用于索引原始数据,以便我们可以使用 Lucene 库进行搜索。
package com.tutorialspoint.lucene;
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
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.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class Indexer {
private IndexWriter writer;
public Indexer(String indexDirectoryPath) throws IOException {
//this directory will contain the indexes
Directory indexDirectory =
FSDirectory.open(new File(indexDirectoryPath));
//create the indexer
writer = new IndexWriter(indexDirectory,
new StandardAnalyzer(Version.LUCENE_36),true,
IndexWriter.MaxFieldLength.UNLIMITED);
}
public void close() throws CorruptIndexException, IOException {
writer.close();
}
private Document getDocument(File file) throws IOException {
Document document = new Document();
//index file contents
Field contentField = new Field(LuceneConstants.CONTENTS, new FileReader(file));
//index file name
Field fileNameField = new Field(LuceneConstants.FILE_NAME,
file.getName(),Field.Store.YES,Field.Index.NOT_ANALYZED);
//index file path
Field filePathField = new Field(LuceneConstants.FILE_PATH,
file.getCanonicalPath(),Field.Store.YES,Field.Index.NOT_ANALYZED);
document.add(contentField);
document.add(fileNameField);
document.add(filePathField);
return document;
}
private void indexFile(File file) throws IOException {
System.out.println("Indexing "+file.getCanonicalPath());
Document document = getDocument(file);
writer.addDocument(document);
}
public int createIndex(String dataDirPath, FileFilter filter)
throws IOException {
//get all files in the data directory
File[] files = new File(dataDirPath).listFiles();
for (File file : files) {
if(!file.isDirectory()
&& !file.isHidden()
&& file.exists()
&& file.canRead()
&& filter.accept(file)
){
indexFile(file);
}
}
return writer.numDocs();
}
}
Searcher.java
此类用于搜索索引程序创建的索引以搜索所需内容。
package com.tutorialspoint.lucene;
import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class Searcher {
IndexSearcher indexSearcher;
QueryParser queryParser;
Query query;
public Searcher(String indexDirectoryPath)
throws IOException {
Directory indexDirectory =
FSDirectory.open(new File(indexDirectoryPath));
indexSearcher = new IndexSearcher(indexDirectory);
queryParser = new QueryParser(Version.LUCENE_36,
LuceneConstants.CONTENTS,
new StandardAnalyzer(Version.LUCENE_36));
}
public TopDocs search( String searchQuery)
throws IOException, ParseException {
query = queryParser.parse(searchQuery);
return indexSearcher.search(query, LuceneConstants.MAX_SEARCH);
}
public Document getDocument(ScoreDoc scoreDoc)
throws CorruptIndexException, IOException {
return indexSearcher.doc(scoreDoc.doc);
}
public void close() throws IOException {
indexSearcher.close();
}
}
LuceneTester.java
此类用于测试 Lucene 库的索引和搜索功能。
package com.tutorialspoint.lucene;
import java.io.IOException;
import org.apache.lucene.document.Document;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
public class LuceneTester {
String indexDir = "E:\\Lucene\\Index";
String dataDir = "E:\\Lucene\\Data";
Indexer indexer;
Searcher searcher;
public static void main(String[] args) {
LuceneTester tester;
try {
tester = new LuceneTester();
tester.createIndex();
tester.search("Mohan");
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
private void createIndex() throws IOException {
indexer = new Indexer(indexDir);
int numIndexed;
long startTime = System.currentTimeMillis();
numIndexed = indexer.createIndex(dataDir, new TextFileFilter());
long endTime = System.currentTimeMillis();
indexer.close();
System.out.println(numIndexed+" File indexed, time taken: "
+(endTime-startTime)+" ms");
}
private void search(String searchQuery) throws IOException, ParseException {
searcher = new Searcher(indexDir);
long startTime = System.currentTimeMillis();
TopDocs hits = searcher.search(searchQuery);
long endTime = System.currentTimeMillis();
System.out.println(hits.totalHits +
" documents found. Time :" + (endTime - startTime));
for(ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.getDocument(scoreDoc);
System.out.println("File: "
+ doc.get(LuceneConstants.FILE_PATH));
}
searcher.close();
}
}
Step 4 - Data & Index directory creation
我们使用了从 record1.txt 到 record10.txt 的 10 个文本文件,其中包含学生的姓名和其他详细信息,并将它们放入目录 E:\Lucene\Data 中。 Test Data 。应该创建索引目录路径为 E:\Lucene\Index 。在运行此程序后,你可以在该文件夹中看到创建的索引文件列表。
Step 5 - Running the program
一旦完成源代码、原始数据、数据目录和索引目录的创建,你就可以编译和运行程序了。要执行此操作,保持 LuceneTester.Java 文件选项卡处于活动状态,并使用 Eclipse IDE 中的 Run 选项或使用 Ctrl + F11 来编译和运行 LuceneTester 应用程序。如果应用程序运行成功,它将在 Eclipse IDE 的控制台中打印以下消息:
Indexing E:\Lucene\Data\record1.txt
Indexing E:\Lucene\Data\record10.txt
Indexing E:\Lucene\Data\record2.txt
Indexing E:\Lucene\Data\record3.txt
Indexing E:\Lucene\Data\record4.txt
Indexing E:\Lucene\Data\record5.txt
Indexing E:\Lucene\Data\record6.txt
Indexing E:\Lucene\Data\record7.txt
Indexing E:\Lucene\Data\record8.txt
Indexing E:\Lucene\Data\record9.txt
10 File indexed, time taken: 109 ms
1 documents found. Time :0
File: E:\Lucene\Data\record4.txt
一旦成功运行该程序,你会在 index directory 中看到以下内容:
Lucene - Indexing Classes
索引进程是 Lucene 提供的核心功能之一。下图说明了索引进程和类别的使用。 IndexWriter 是索引过程中最重要的核心组件。
我们向包含 Field(s) 的 Document(s) 添加 IndexWriter,它使用 Analyzer 分析 Document(s) ,然后根据需要创建/打开/编辑索引,并将其存储/更新到 Directory 中。IndexWriter 用于更新或创建索引。它不用于读取索引。
Indexing Classes
以下是索引过程中常用的一些类。
S.No. |
Class & Description |
1 |
IndexWriter 此类充当在索引过程中创建/更新索引的核心组件。 |
2 |
Directory 此类代表索引的存储位置。 |
3 |
Analyzer 此类负责分析文档并从要索引的文本中获取令牌/单词。如果不进行分析,IndexWriter 便无法创建索引。 |
4 |
Document 此类表示具有字段的虚拟文档,其中字段是可以包含物理文档的内容、其元数据等的类。Analyzer 只能识别 Document。 |
5 |
Field 这是索引过程的最低单元或起点。它表示键值对关系,其中密钥用于标识要索引的值。让我们假设用于表示文档内容的字段的键为“内容”,值可能包含文档的部分或全部文本或数字内容。Lucene 只能索引文本或数字内容。 |
Lucene - Searching Classes
搜索这一过程也是 Lucene 提供的核心功能之一。它的流程类似于索引过程。Lucene 的基本搜索可以使用以下类,它们也可以被称为所有搜索相关操作的基础类。
Searching Classes
以下是搜索过程中常用的类列表。
S.No. |
Class & Description |
1 |
IndexSearcher 这个类充当核心组件,用于读取/搜索在索引过程中生成之后的索引。它获取指向包含索引的位置的目录实例。 |
2 |
Term 这个类是搜索的最小单位。它类似于索引过程中的 Field。 |
3 |
Query Query 是一个抽象类,包含各种实用方法,是 Lucene 在搜索过程中使用的所有类型查询的父类。 |
4 |
TermQuery TermQuery 是最常用的查询对象,并且是 Lucene 可使用的许多复杂查询的基础。 |
5 |
TopDocs TopDocs 指向与搜索条件匹配的排名前 N 的搜索结果。它是一个简单的指针容器,用于指向文档,这些文档是搜索结果的输出。 |
Lucene - Indexing Process
索引过程是 Lucene 提供的核心功能之一。下图说明了索引过程和类的使用。IndexWriter 是索引过程的最重要和核心组件。
我们将包含 Field 的 Document 添加到 IndexWriter,它使用 Analyzer 分析 Document,然后根据需要创建/打开/编辑索引并将其存储/更新到 Directory 中。IndexWriter 用于更新或创建索引。它不用于读取索引。
现在,我们将向您展示逐步的过程,以通过一个基本的示例开始了解索引过程。
Create a document
-
创建一个从文本文件中获取 Lucene 文档的方法。
-
创建各种类型的字段,这些字段是包含作为名称的键和作为要索引的内容的值的关键值对。
.
-
设置该字段是否要分析。在我们的例子中,只有内容需要分析,因为它可能包含诸如 a、am、are、an 等不适用于搜索操作的数据。
.
-
将新创建的字段添加到文档对象,并将其返回给调用方法。
private Document getDocument(File file) throws IOException {
Document document = new Document();
//index file contents
Field contentField = new Field(LuceneConstants.CONTENTS,
new FileReader(file));
//index file name
Field fileNameField = new Field(LuceneConstants.FILE_NAME,
file.getName(),
Field.Store.YES,Field.Index.NOT_ANALYZED);
//index file path
Field filePathField = new Field(LuceneConstants.FILE_PATH,
file.getCanonicalPath(),
Field.Store.YES,Field.Index.NOT_ANALYZED);
document.add(contentField);
document.add(fileNameField);
document.add(filePathField);
return document;
}
Create a IndexWriter
IndexWriter 类充当核心组件,在索引过程中创建/更新索引。按照以下步骤创建 IndexWriter −
Step 1 − 创建 IndexWriter 对象。
Step 2 − 创建 Lucene 目录,该目录应该指向存储索引的位置。
Step 3 − 使用索引目录、具有版本信息及其他必需/可选参数的标准分析器初始化创建的 IndexWriter 对象。
private IndexWriter writer;
public Indexer(String indexDirectoryPath) throws IOException {
//this directory will contain the indexes
Directory indexDirectory =
FSDirectory.open(new File(indexDirectoryPath));
//create the indexer
writer = new IndexWriter(indexDirectory,
new StandardAnalyzer(Version.LUCENE_36),true,
IndexWriter.MaxFieldLength.UNLIMITED);
}
Start Indexing Process
以下程序展示了如何启动索引过程 −
private void indexFile(File file) throws IOException {
System.out.println("Indexing "+file.getCanonicalPath());
Document document = getDocument(file);
writer.addDocument(document);
}
Example Application
为了测试索引过程,我们需要创建一个 Lucene 应用程序测试。
Step |
Description |
1 |
在包 com.tutorialspoint.lucene 中创建一个名为 LuceneFirstApplication 的项目,如 Lucene - First Application 章节中所解释。您还可以使用 Lucene - First Application 章节中创建的项目,以了解索引过程。 |
2 |
如 Lucene - First Application 章节中所解释,创建 LuceneConstants.java、TextFileFilter.java 和 Indexer.java。保持其余文件不变。 |
3 |
如下所示创建 LuceneTester.java。 |
4 |
清理并构建应用程序,以确保业务逻辑按照要求工作。 |
LuceneConstants.java
此类用于提供将在整个示例应用程序中使用的各种常量。
package com.tutorialspoint.lucene;
public class LuceneConstants {
public static final String CONTENTS = "contents";
public static final String FILE_NAME = "filename";
public static final String FILE_PATH = "filepath";
public static final int MAX_SEARCH = 10;
}
TextFileFilter.java
此类用作 .txt 文件过滤器。
package com.tutorialspoint.lucene;
import java.io.File;
import java.io.FileFilter;
public class TextFileFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
return pathname.getName().toLowerCase().endsWith(".txt");
}
}
Indexer.java
此类用于索引原始数据,以便我们可以使用 Lucene 库进行搜索。
package com.tutorialspoint.lucene;
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
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.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class Indexer {
private IndexWriter writer;
public Indexer(String indexDirectoryPath) throws IOException {
//this directory will contain the indexes
Directory indexDirectory =
FSDirectory.open(new File(indexDirectoryPath));
//create the indexer
writer = new IndexWriter(indexDirectory,
new StandardAnalyzer(Version.LUCENE_36),true,
IndexWriter.MaxFieldLength.UNLIMITED);
}
public void close() throws CorruptIndexException, IOException {
writer.close();
}
private Document getDocument(File file) throws IOException {
Document document = new Document();
//index file contents
Field contentField = new Field(LuceneConstants.CONTENTS,
new FileReader(file));
//index file name
Field fileNameField = new Field(LuceneConstants.FILE_NAME,
file.getName(),
Field.Store.YES,Field.Index.NOT_ANALYZED);
//index file path
Field filePathField = new Field(LuceneConstants.FILE_PATH,
file.getCanonicalPath(),
Field.Store.YES,Field.Index.NOT_ANALYZED);
document.add(contentField);
document.add(fileNameField);
document.add(filePathField);
return document;
}
private void indexFile(File file) throws IOException {
System.out.println("Indexing "+file.getCanonicalPath());
Document document = getDocument(file);
writer.addDocument(document);
}
public int createIndex(String dataDirPath, FileFilter filter)
throws IOException {
//get all files in the data directory
File[] files = new File(dataDirPath).listFiles();
for (File file : files) {
if(!file.isDirectory()
&& !file.isHidden()
&& file.exists()
&& file.canRead()
&& filter.accept(file)
){
indexFile(file);
}
}
return writer.numDocs();
}
}
LuceneTester.java
此类用于测试 Lucene 库的索引功能。
package com.tutorialspoint.lucene;
import java.io.IOException;
public class LuceneTester {
String indexDir = "E:\\Lucene\\Index";
String dataDir = "E:\\Lucene\\Data";
Indexer indexer;
public static void main(String[] args) {
LuceneTester tester;
try {
tester = new LuceneTester();
tester.createIndex();
} catch (IOException e) {
e.printStackTrace();
}
}
private void createIndex() throws IOException {
indexer = new Indexer(indexDir);
int numIndexed;
long startTime = System.currentTimeMillis();
numIndexed = indexer.createIndex(dataDir, new TextFileFilter());
long endTime = System.currentTimeMillis();
indexer.close();
System.out.println(numIndexed+" File indexed, time taken: "
+(endTime-startTime)+" ms");
}
}
Data & Index Directory Creation
我们使用了从 record1.txt 到 record10.txt 的 10 个文本文件,其中包含学生姓名和其他详细信息,并将它们放在目录 E:\Lucene\Data. Test Data 中。索引目录路径应创建为 E:\Lucene\Index 。在此程序运行结束后,您可以在该文件夹中看到创建的索引文件列表。
Running the Program
创建完源文件、原始数据、数据目录和索引目录后,就可以编译并运行程序。为此,保持 LuceneTester.Java 文件选项卡处于活动状态,然后使用 Eclipse IDE 中提供的 Run 选项或使用 Ctrl + F11 编译并运行 LuceneTester 应用程序。如果您的应用程序运行成功,它将打印 Eclipse IDE 控制台中的以下消息 −
Indexing E:\Lucene\Data\record1.txt
Indexing E:\Lucene\Data\record10.txt
Indexing E:\Lucene\Data\record2.txt
Indexing E:\Lucene\Data\record3.txt
Indexing E:\Lucene\Data\record4.txt
Indexing E:\Lucene\Data\record5.txt
Indexing E:\Lucene\Data\record6.txt
Indexing E:\Lucene\Data\record7.txt
Indexing E:\Lucene\Data\record8.txt
Indexing E:\Lucene\Data\record9.txt
10 File indexed, time taken: 109 ms
成功运行程序后,您将在 index directory − 中看到以下内容
Lucene - Indexing Operations
在本章中,我们将讨论索引的四个主要操作。这些操作在不同的时间段很有用,并在软件搜索应用程序中使用。
Indexing Operations
以下是索引过程中常用的操作列表。
S.No. |
Operation & Description |
1 |
Add Document 此操作用于索引过程的初始阶段,以便对新内容进行索引。 |
2 |
Update Document 此操作用于更新索引以反映已更新内容的变化。它类似于重新创建索引。 |
3 |
Delete Document 此操作用于更新索引,以排除不需要索引/搜索的文档。 |
4 |
Field Options 字段选项指定方法或控件,用于使字段的内容可搜索。 |
Lucene - Search Operation
搜索过程是 Lucene 提供的核心功能之一。下图说明了该过程及其用途。IndexSearcher 是搜索过程的核心组件之一。
我们首先创建包含索引的 Directory(ies),然后将其传递给使用 IndexReader 打开 Directory 的 IndexSearcher。然后,我们使用 Term 创建一个 Query,并使用 IndexSearcher 进行搜索,方法是将 Query 传递给搜索器。IndexSearcher 返回一个 TopDocs 对象,其中包含搜索详细信息以及搜索操作结果的 Document 的文档 ID。
现在,我们将向您展示一个逐步的方法,并帮助您理解使用基本示例进行的索引过程。
Create a QueryParser
QueryParser 类将用户输入的输入解析为 Lucene 理解的格式查询。按照以下步骤创建 QueryParser −
Step 1 − 创建 QueryParser 对象。
Step 2 − 使用具有版本信息和要在此查询上运行的索引名称的标准分析器初始化创建的 QueryParser 对象。
QueryParser queryParser;
public Searcher(String indexDirectoryPath) throws IOException {
queryParser = new QueryParser(Version.LUCENE_36,
LuceneConstants.CONTENTS,
new StandardAnalyzer(Version.LUCENE_36));
}
Create a IndexSearcher
IndexSearcher 类充当搜索器索引的核心组件,该索引在索引过程中创建。按照以下步骤创建 IndexSearcher −
Step 1 − 创建 IndexSearcher 对象。
Step 2 − 创建 Lucene 目录,该目录应该指向存储索引的位置。
Step 3 − 使用索引目录初始化创建的 IndexSearcher 对象。
IndexSearcher indexSearcher;
public Searcher(String indexDirectoryPath) throws IOException {
Directory indexDirectory =
FSDirectory.open(new File(indexDirectoryPath));
indexSearcher = new IndexSearcher(indexDirectory);
}
Make search
按照以下步骤进行搜索 −
Step 1 − 通过 QueryParser 解析搜索表达式来创建 Query 对象。
Step 2 − 通过调用 IndexSearcher.search() 方法进行搜索。
Query query;
public TopDocs search( String searchQuery) throws IOException, ParseException {
query = queryParser.parse(searchQuery);
return indexSearcher.search(query, LuceneConstants.MAX_SEARCH);
}
Get the Document
以下程序显示如何获取文档。
public Document getDocument(ScoreDoc scoreDoc)
throws CorruptIndexException, IOException {
return indexSearcher.doc(scoreDoc.doc);
}
Close IndexSearcher
以下程序显示如何关闭 IndexSearcher。
public void close() throws IOException {
indexSearcher.close();
}
Example Application
让我们创建一个测试 Lucene 应用程序来测试搜索过程。
Step |
Description |
1 |
在包 com.tutorialspoint.lucene 下使用名称 LuceneFirstApplication 创建一个项目,如 Lucene - 第一个应用程序章节中所述。您还可以在此章节中使用如该章节中创建的项目,以便理解搜索过程。 |
2 |
创建 LuceneConstants.java、TextFileFilter.java 和 Searcher.java,如 Lucene - 第一个应用程序章节中所述。保持其余文件不变。 |
3 |
如下所示创建 LuceneTester.java。 |
4 |
清理并构建应用程序以确保业务逻辑按需求工作。 |
LuceneConstants.java
此类用于提供将在整个示例应用程序中使用的各种常量。
package com.tutorialspoint.lucene;
public class LuceneConstants {
public static final String CONTENTS = "contents";
public static final String FILE_NAME = "filename";
public static final String FILE_PATH = "filepath";
public static final int MAX_SEARCH = 10;
}
TextFileFilter.java
此类用作 .txt 文件过滤器。
package com.tutorialspoint.lucene;
import java.io.File;
import java.io.FileFilter;
public class TextFileFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
return pathname.getName().toLowerCase().endsWith(".txt");
}
}
Searcher.java
此类用于读取原始数据上创建的索引并使用 Lucene 库搜索数据。
package com.tutorialspoint.lucene;
import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class Searcher {
IndexSearcher indexSearcher;
QueryParser queryParser;
Query query;
public Searcher(String indexDirectoryPath) throws IOException {
Directory indexDirectory =
FSDirectory.open(new File(indexDirectoryPath));
indexSearcher = new IndexSearcher(indexDirectory);
queryParser = new QueryParser(Version.LUCENE_36,
LuceneConstants.CONTENTS,
new StandardAnalyzer(Version.LUCENE_36));
}
public TopDocs search( String searchQuery)
throws IOException, ParseException {
query = queryParser.parse(searchQuery);
return indexSearcher.search(query, LuceneConstants.MAX_SEARCH);
}
public Document getDocument(ScoreDoc scoreDoc)
throws CorruptIndexException, IOException {
return indexSearcher.doc(scoreDoc.doc);
}
public void close() throws IOException {
indexSearcher.close();
}
}
LuceneTester.java
此类用于测试 Lucene 库的搜索功能。
package com.tutorialspoint.lucene;
import java.io.IOException;
import org.apache.lucene.document.Document;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
public class LuceneTester {
String indexDir = "E:\\Lucene\\Index";
String dataDir = "E:\\Lucene\\Data";
Searcher searcher;
public static void main(String[] args) {
LuceneTester tester;
try {
tester = new LuceneTester();
tester.search("Mohan");
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
private void search(String searchQuery) throws IOException, ParseException {
searcher = new Searcher(indexDir);
long startTime = System.currentTimeMillis();
TopDocs hits = searcher.search(searchQuery);
long endTime = System.currentTimeMillis();
System.out.println(hits.totalHits +
" documents found. Time :" + (endTime - startTime) +" ms");
for(ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.getDocument(scoreDoc);
System.out.println("File: "+ doc.get(LuceneConstants.FILE_PATH));
}
searcher.close();
}
}
Data & Index Directory Creation
我们使用了 10 个名为 record1.txt 到 record10.txt 的文本文件,其中包含学生姓名和其他详细信息,并将它们放入目录 E:\Lucene\Data. 中。 Test Data . 索引目录路径应创建为 E:\Lucene\Index。在章节 Lucene - Indexing Process 中运行索引程序后,您可以在该文件夹中看到所创建的索引文件列表。
Lucene - Query Programming
我们在前一章 Lucene - Search Operation 中看到,Lucene 使用 IndexSearcher 进行搜索,并且它使用 QueryParser 创建的 Query 对象作为输入。在本章中,我们将讨论各种类型的 Query 对象以及以编程方式创建它们的不同方法。创建不同类型的 Query 对象可以控制要进行的搜索类型。
考虑许多应用程序提供的高级搜索案例,在这些应用程序中用户有多个选项来限定搜索结果。通过查询编程,我们可以非常轻松地实现相同目标。
以下是我们稍后将讨论的查询类型列表。
S.No. |
Class & Description |
1 |
TermQuery 此类用作创建/更新索引过程中的核心组件。 |
2 |
TermRangeQuery 当需要搜索一系列文本术语时,将使用 TermRangeQuery。 |
3 |
PrefixQuery 可以使用 PrefixQuery 匹配索引以指定字符串开头的文档。 |
4 |
BooleanQuery 可以使用 BooleanQuery 使用 AND, OR 或 NOT 运算符搜索多个查询的结果文档。 |
5 |
PhraseQuery 可以使用短语查询搜索包含特定术语序列的文档。 |
6 |
WildCardQuery 可以使用通配符查询使用通配符(如“*”表示任何字符序列、“?”表示匹配单个字符)搜索文档。 |
7 |
FuzzyQuery 可以使用模糊查询使用基于编辑距离算法的近似搜索搜索文档。 |
8 |
MatchAllDocsQuery 如其名称所示,MatchAllDocsQuery 匹配所有文档。 |
Lucene - Analysis
在前面的章节中,我们了解到 Lucene 使用 IndexWriter 使用 Analyzer 分析文档,然后根据需要创建/打开/编辑索引。在本节中,我们将讨论分析过程中使用的各种类型的 Analyzer 对象和其他相关对象。了解分析过程和分析器的运行机制将让你深入了解 Lucene 如何为文档编制索引。
以下是我们将会逐步讨论的对象列表。
S.No. |
Class & Description |
1 |
Token Token 表示文档中的文本或单词,具有相关详细信息,如其元数据(位置、开始偏移量、结束偏移量、标记类型及其位置增量)。 |
2 |
TokenStream TokenStream 是分析过程的输出,由一系列标记组成。它是一个抽象类。 |
3 |
Analyzer 这是每种 Analyzer 类型的抽象基类。 |
4 |
WhitespaceAnalyzer 此分析器根据空格分割文档中的文本。 |
5 |
SimpleAnalyzer 此分析器根据非字母字符分割文档中的文本,并将文本转换为小写。 |
6 |
StopAnalyzer 此分析器的作用与 SimpleAnalyzer 相同,并会删除 'a', 'an', 'the', 等常用词。 |
7 |
StandardAnalyzer 这是最复杂的分析器,能够处理名称、电子邮件地址等。它将每个标记转换为小写,并删除常见单词和标点符号(如有)。 |
Lucene - Sorting
在本章中,我们将了解 Lucene 在默认情况下提供的或者可以根据需要进行处理的搜索结果的排序顺序。
Sorting by Relevance
这是 Lucene 使用的默认排序模式。Lucene 根据最相关的点击结果提供结果。
private void sortUsingRelevance(String searchQuery)
throws IOException, ParseException {
searcher = new Searcher(indexDir);
long startTime = System.currentTimeMillis();
//create a term to search file name
Term term = new Term(LuceneConstants.FILE_NAME, searchQuery);
//create the term query object
Query query = new FuzzyQuery(term);
searcher.setDefaultFieldSortScoring(true, false);
//do the search
TopDocs hits = searcher.search(query,Sort.RELEVANCE);
long endTime = System.currentTimeMillis();
System.out.println(hits.totalHits +
" documents found. Time :" + (endTime - startTime) + "ms");
for(ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.getDocument(scoreDoc);
System.out.print("Score: "+ scoreDoc.score + " ");
System.out.println("File: "+ doc.get(LuceneConstants.FILE_PATH));
}
searcher.close();
}
Sorting by IndexOrder
Lucene 使用该排序模式。在此处,将首先在搜索结果中显示首次编入索引的文档。
private void sortUsingIndex(String searchQuery)
throws IOException, ParseException {
searcher = new Searcher(indexDir);
long startTime = System.currentTimeMillis();
//create a term to search file name
Term term = new Term(LuceneConstants.FILE_NAME, searchQuery);
//create the term query object
Query query = new FuzzyQuery(term);
searcher.setDefaultFieldSortScoring(true, false);
//do the search
TopDocs hits = searcher.search(query,Sort.INDEXORDER);
long endTime = System.currentTimeMillis();
System.out.println(hits.totalHits +
" documents found. Time :" + (endTime - startTime) + "ms");
for(ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.getDocument(scoreDoc);
System.out.print("Score: "+ scoreDoc.score + " ");
System.out.println("File: "+ doc.get(LuceneConstants.FILE_PATH));
}
searcher.close();
}
Example Application
让我们创建一个测试 Lucene 应用程序来测试排序过程。
Step |
Description |
1 |
在包 com.tutorialspoint.lucene 下使用名称 LuceneFirstApplication 创建一个项目,如 Lucene - 第一个应用程序章节中所述。您还可以在此章节中使用如该章节中创建的项目,以便理解搜索过程。 |
2 |
创建 LuceneConstants.java 和 Searcher.java,如 Lucene - 第一章应用程序中所述。保持其余文件不变。 |
3 |
如下所示创建 LuceneTester.java。 |
4 |
清理并构建应用程序以确保业务逻辑按照要求正常工作。 |
LuceneConstants.java
此类用于提供将在整个示例应用程序中使用的各种常量。
package com.tutorialspoint.lucene;
public class LuceneConstants {
public static final String CONTENTS = "contents";
public static final String FILE_NAME = "filename";
public static final String FILE_PATH = "filepath";
public static final int MAX_SEARCH = 10;
}
Searcher.java
此类用于读取原始数据上创建的索引并使用 Lucene 库搜索数据。
package com.tutorialspoint.lucene;
import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class Searcher {
IndexSearcher indexSearcher;
QueryParser queryParser;
Query query;
public Searcher(String indexDirectoryPath) throws IOException {
Directory indexDirectory
= FSDirectory.open(new File(indexDirectoryPath));
indexSearcher = new IndexSearcher(indexDirectory);
queryParser = new QueryParser(Version.LUCENE_36,
LuceneConstants.CONTENTS,
new StandardAnalyzer(Version.LUCENE_36));
}
public TopDocs search( String searchQuery)
throws IOException, ParseException {
query = queryParser.parse(searchQuery);
return indexSearcher.search(query, LuceneConstants.MAX_SEARCH);
}
public TopDocs search(Query query)
throws IOException, ParseException {
return indexSearcher.search(query, LuceneConstants.MAX_SEARCH);
}
public TopDocs search(Query query,Sort sort)
throws IOException, ParseException {
return indexSearcher.search(query,
LuceneConstants.MAX_SEARCH,sort);
}
public void setDefaultFieldSortScoring(boolean doTrackScores,
boolean doMaxScores) {
indexSearcher.setDefaultFieldSortScoring(
doTrackScores,doMaxScores);
}
public Document getDocument(ScoreDoc scoreDoc)
throws CorruptIndexException, IOException {
return indexSearcher.doc(scoreDoc.doc);
}
public void close() throws IOException {
indexSearcher.close();
}
}
LuceneTester.java
此类用于测试 Lucene 库的搜索功能。
package com.tutorialspoint.lucene;
import java.io.IOException;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TopDocs;
public class LuceneTester {
String indexDir = "E:\\Lucene\\Index";
String dataDir = "E:\\Lucene\\Data";
Indexer indexer;
Searcher searcher;
public static void main(String[] args) {
LuceneTester tester;
try {
tester = new LuceneTester();
tester.sortUsingRelevance("cord3.txt");
tester.sortUsingIndex("cord3.txt");
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
private void sortUsingRelevance(String searchQuery)
throws IOException, ParseException {
searcher = new Searcher(indexDir);
long startTime = System.currentTimeMillis();
//create a term to search file name
Term term = new Term(LuceneConstants.FILE_NAME, searchQuery);
//create the term query object
Query query = new FuzzyQuery(term);
searcher.setDefaultFieldSortScoring(true, false);
//do the search
TopDocs hits = searcher.search(query,Sort.RELEVANCE);
long endTime = System.currentTimeMillis();
System.out.println(hits.totalHits +
" documents found. Time :" + (endTime - startTime) + "ms");
for(ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.getDocument(scoreDoc);
System.out.print("Score: "+ scoreDoc.score + " ");
System.out.println("File: "+ doc.get(LuceneConstants.FILE_PATH));
}
searcher.close();
}
private void sortUsingIndex(String searchQuery)
throws IOException, ParseException {
searcher = new Searcher(indexDir);
long startTime = System.currentTimeMillis();
//create a term to search file name
Term term = new Term(LuceneConstants.FILE_NAME, searchQuery);
//create the term query object
Query query = new FuzzyQuery(term);
searcher.setDefaultFieldSortScoring(true, false);
//do the search
TopDocs hits = searcher.search(query,Sort.INDEXORDER);
long endTime = System.currentTimeMillis();
System.out.println(hits.totalHits +
" documents found. Time :" + (endTime - startTime) + "ms");
for(ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.getDocument(scoreDoc);
System.out.print("Score: "+ scoreDoc.score + " ");
System.out.println("File: "+ doc.get(LuceneConstants.FILE_PATH));
}
searcher.close();
}
}
Data & Index Directory Creation
我们已使用 10 个文本文件(record1.txt 到 record10.txt),其中包含学生姓名和其他详细信息,并将它们放在 E:\Lucene\Data. Test Data 目录中。应将索引目录路径创建为 E:\Lucene\Index。在本章的 Lucene - Indexing Process 中运行索引程序后,您可以在该文件夹中看到创建的索引文件列表。
Running the Program
创建完源代码、原始数据、数据目录、索引目录和索引后,您可以编译并运行程序。为此,保持 LuceneTester.Java 文件选项卡处于活动状态,然后使用 Eclipse IDE 中的“运行”选项,或使用 Ctrl + F11 编译并运行 LuceneTester 应用程序。如果您的应用程序运行成功,它将在 Eclipse IDE 的控制台中打印以下消息:
10 documents found. Time :31ms
Score: 1.3179655 File: E:\Lucene\Data\record3.txt
Score: 0.790779 File: E:\Lucene\Data\record1.txt
Score: 0.790779 File: E:\Lucene\Data\record2.txt
Score: 0.790779 File: E:\Lucene\Data\record4.txt
Score: 0.790779 File: E:\Lucene\Data\record5.txt
Score: 0.790779 File: E:\Lucene\Data\record6.txt
Score: 0.790779 File: E:\Lucene\Data\record7.txt
Score: 0.790779 File: E:\Lucene\Data\record8.txt
Score: 0.790779 File: E:\Lucene\Data\record9.txt
Score: 0.2635932 File: E:\Lucene\Data\record10.txt
10 documents found. Time :0ms
Score: 0.790779 File: E:\Lucene\Data\record1.txt
Score: 0.2635932 File: E:\Lucene\Data\record10.txt
Score: 0.790779 File: E:\Lucene\Data\record2.txt
Score: 1.3179655 File: E:\Lucene\Data\record3.txt
Score: 0.790779 File: E:\Lucene\Data\record4.txt
Score: 0.790779 File: E:\Lucene\Data\record5.txt
Score: 0.790779 File: E:\Lucene\Data\record6.txt
Score: 0.790779 File: E:\Lucene\Data\record7.txt
Score: 0.790779 File: E:\Lucene\Data\record8.txt
Score: 0.790779 File: E:\Lucene\Data\record9.txt