Lucene - 快速指南
Lucene - 概述
Lucene 是一个简单但功能强大的基于 Java 的搜索库。它可以在任何应用程序中使用以添加搜索功能。Lucene 是一个开源项目。它是可扩展的。这个高性能库用于索引和搜索几乎任何类型的文本。Lucene 库提供任何搜索应用程序所需的核心操作。索引和搜索。
搜索应用程序如何工作?
搜索应用程序执行以下全部或部分操作 -
步 | 标题 | 描述 |
---|---|---|
1 | 获取原始内容 |
任何搜索应用的第一步都是收集要进行搜索应用的目标内容。 |
2 | 构建文档 |
下一步是根据原始内容构建文档,搜索应用程序可以轻松理解和解释该文档。 |
3 | 分析文档 |
在索引过程开始之前,将分析文档以确定文本的哪一部分是要索引的候选部分。此过程是分析文档的地方。 |
4 | 索引文档 |
构建和分析文档后,下一步就是对它们建立索引,以便可以根据某些键而不是文档的全部内容来检索该文档。索引过程类似于书末的索引,其中常用单词及其页码显示,以便可以快速跟踪这些单词,而不是搜索整本书。 |
5 | 搜索用户界面 |
一旦索引数据库准备就绪,应用程序就可以进行任何搜索。为了方便用户进行搜索,应用程序必须向用户提供一种方法或用户界面,用户可以在其中输入文本并开始搜索过程。 |
6 | 构建查询 |
一旦用户发出搜索文本的请求,应用程序应该使用该文本准备一个查询对象,该对象可用于查询索引数据库以获取相关详细信息。 |
7 | 搜索查询 |
然后使用查询对象检查索引数据库以获取相关详细信息和内容文档。 |
8 | 渲染结果 |
收到结果后,应用程序应决定如何使用用户界面向用户显示结果。乍一看要显示多少信息等等。 |
除了这些基本操作之外,搜索应用程序还可以提供管理用户界面并帮助应用程序管理员根据用户配置文件控制搜索级别。搜索结果分析是任何搜索应用程序的另一个重要且高级的方面。
Lucene 在搜索应用中的作用
Lucene在上面提到的步骤2到步骤7中发挥作用,并提供类来完成所需的操作。简而言之,Lucene 是任何搜索应用程序的核心,提供与索引和搜索相关的重要操作。获取内容并显示结果留给应用程序部分处理。
在下一章中,我们将使用 Lucene 搜索库执行一个简单的搜索应用程序。
Lucene - 环境设置
本教程将指导您如何准备开发环境以开始使用 Spring 框架。本教程还将教您如何在设置 Spring 框架之前在计算机上设置 JDK、Tomcat 和 Eclipse -
第 1 步 - Java 开发工具包 (JDK) 设置
您可以从 Oracle 的 Java 站点下载最新版本的 SDK:Java SE 下载。您将在下载的文件中找到安装 JDK 的说明;按照给定的说明安装和配置设置。最后设置 PATH 和 JAVA_HOME 环境变量以引用包含 Java 和 javac 的目录,通常分别为 java_install_dir/bin 和 java_install_dir。
如果您运行的是 Windows 并将 JDK 安装在 C:\jdk1.6.0_15 中,则必须将以下行放入 C:\autoexec.bat 文件中。
set PATH = C:\jdk1.6.0_15\bin;%PATH% set JAVA_HOME = C:\jdk1.6.0_15
或者,在 Windows NT/2000/XP 上,您也可以右键单击“我的电脑”,选择“属性”,然后选择“高级”,然后选择“环境变量”。然后,您将更新PATH值并按“确定”按钮。
在 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 等集成开发环境 (IDE),请编译并运行一个简单的程序以确认 IDE 知道您安装 Java 的位置,否则请按照中给出的正确设置IDE 的文档。
第 2 步 - Eclipse IDE 设置
本教程中的所有示例都是使用Eclipse IDE编写的。所以我建议你应该在你的机器上安装最新版本的 Eclipse。
要安装 Eclipse IDE,请从https://www.eclipse.org/downloads/下载最新的 Eclipse 二进制文件。下载安装后,将二进制发行版解压到一个方便的位置。例如,在Windows 上的 C:\eclipse 中,或在 Linux/Unix 上的 /usr/local/eclipse 中,最后适当地设置 PATH 变量。
可以通过在 Windows 机器上执行以下命令来启动 Eclipse,也可以直接双击eclipse.exe
%C:\eclipse\eclipse.exe
可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令来启动 Eclipse -
$/usr/local/eclipse/eclipse
成功启动后,应该显示以下结果 -
第 3 步 - 设置 Lucene 框架库
如果启动成功,那么您可以继续设置 Lucene 框架。以下是在您的计算机上下载并安装框架的简单步骤。
https://archive.apache.org/dist/lucene/java/3.6.2/
选择是要在 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 - 第一个应用程序
在本章中,我们将学习使用 Lucene Framework 进行实际编程。在开始使用 Lucene 框架编写第一个示例之前,您必须确保已按照Lucene - 环境设置教程中的说明正确设置 Lucene 环境。建议您具备 Eclipse IDE 的使用知识。
现在让我们继续编写一个简单的搜索应用程序,它将打印找到的搜索结果的数量。我们还将看到在此过程中创建的索引列表。
第 1 步 - 创建 Java 项目
第一步是使用 Eclipse IDE 创建一个简单的 Java 项目。按照选项“文件”>“新建”->“项目”,最后从向导列表中选择“Java 项目向导”。现在使用向导窗口将您的项目命名为LuceneFirstApplication,如下所示 -
成功创建项目后,您的项目资源管理器中将包含以下内容-
第 2 步 - 添加所需的库
现在让我们在项目中添加 Lucene 核心框架库。为此,右键单击您的项目名称LuceneFirstApplication,然后按照上下文菜单中提供的以下选项进行操作:构建路径 -> 配置构建路径以显示 Java 构建路径窗口,如下所示 -
现在使用“库”选项卡下的“添加外部 JAR”按钮从 Lucene 安装目录添加以下核心 JAR -
- lucene-core-3.6.2
第 3 步 - 创建源文件
现在让我们在LuceneFirstApplication项目下创建实际的源文件。首先我们需要创建一个名为com.tutorialspoint.lucene 的包。为此,请右键单击包资源管理器部分中的 src 并遵循选项:新建 -> 包。
接下来我们将在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; }
文本文件过滤器.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"); } }
索引器.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(); } }
搜索器.java
该类用于搜索Indexer创建的索引,以搜索请求的内容。
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(); } }
第 4 步 - 创建数据和索引目录
我们使用了从 record1.txt 到 record10.txt 的 10 个文本文件,其中包含学生的姓名和其他详细信息,并将它们放在目录E:\Lucene\Data中。测试数据。索引目录路径应创建为E:\Lucene\Index。运行该程序后,您可以看到在该文件夹中创建的索引文件列表。
第 5 步 - 运行程序
完成源、原始数据、数据目录和索引目录的创建后,您就可以编译和运行程序了。为此,请保持LuceneTester.Java文件选项卡处于活动状态,并使用Eclipse IDE 中提供的“运行”选项或使用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
成功运行程序后,您的索引目录中将包含以下内容-
Lucene - 索引类
索引过程是Lucene提供的核心功能之一。下图说明了索引过程和类的使用。IndexWriter是索引过程中最重要、也是最核心的组件。
我们将包含字段的文档添加到 IndexWriter,它使用分析器分析文档,然后根据需要创建/打开/编辑索引,并将它们存储/更新到 Directory中。IndexWriter 用于更新或创建索引。它不用于读取索引。
索引类
以下是索引过程中常用的类的列表。
编号 | 类别和描述 |
---|---|
1 | 索引编写器
此类充当在索引过程中创建/更新索引的核心组件。 |
2 | 目录
该类表示索引的存储位置。 |
3 | 分析仪
此类负责分析文档并从要索引的文本中获取标记/单词。如果没有完成分析,IndexWriter 就无法创建索引。 |
4 | 文档
此类表示带有字段的虚拟文档,其中字段是一个对象,可以包含物理文档的内容、元数据等。分析器只能理解文档。 |
5 | 场地
这是索引过程的最低单元或起点。它表示键值对关系,其中键用于标识要索引的值。让我们假设用于表示文档内容的字段将具有作为“内容”的键,并且该值可以包含文档的部分或全部文本或数字内容。Lucene 只能索引文本或数字内容。 |
Lucene - 搜索类
搜索过程又是Lucene 提供的核心功能之一。其流程与索引过程类似。Lucene 的基本搜索可以使用以下类进行,这些类也可以称为所有搜索相关操作的基础类。
搜索课程
以下是搜索过程中常用的类列表。
编号 | 类别和描述 |
---|---|
1 | 索引搜索器
此类充当核心组件,读取/搜索索引过程后创建的索引。它需要指向包含索引的位置的目录实例。 |
2 | 学期
该类是搜索的最低单位。它类似于索引过程中的Field。 |
3 | 询问
Query 是一个抽象类,包含各种实用方法,是 Lucene 在搜索过程中使用的所有类型查询的父类。 |
4 | 术语查询
TermQuery 是最常用的查询对象,是 Lucene 可以使用的许多复杂查询的基础。 |
5 | 热门文档
TopDocs 指向符合搜索条件的前 N 个搜索结果。它是一个简单的指针容器,指向作为搜索结果输出的文档。 |
Lucene - 索引过程
索引过程是Lucene提供的核心功能之一。下图说明了索引过程和类的使用。IndexWriter是索引过程中最重要、最核心的组件。
我们将包含字段的文档添加到 IndexWriter,它使用分析器分析文档,然后根据需要创建/打开/编辑索引,并将它们存储/更新到Directory中。IndexWriter用于更新或创建索引。它不用于读取索引。
现在,我们将使用一个基本示例向您展示逐步的过程,以帮助您开始理解索引过程。
创建文档
创建一个从文本文件获取 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; }
创建一个索引写入器
IndexWriter 类充当核心组件,在索引过程中创建/更新索引。按照以下步骤创建 IndexWriter -
步骤 1 - 创建 IndexWriter 对象。
步骤 2 - 创建一个 Lucene 目录,该目录应指向要存储索引的位置。
步骤 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); }
开始索引过程
以下程序显示了如何启动索引过程 -
private void indexFile(File file) throws IOException { System.out.println("Indexing "+file.getCanonicalPath()); Document document = getDocument(file); writer.addDocument(document); }
应用示例
为了测试索引过程,我们需要创建一个 Lucene 应用程序测试。
步 | 描述 |
---|---|
1 | 在com.tutorialspoint.lucene包下创建一个名为LuceneFirstApplication 的项目,如Lucene - First Application 章节中所述。您还可以使用本章中在Lucene - 第一个应用程序章节中创建的项目来了解索引过程。 |
2 | 按照Lucene - 第一个应用程序章节中的说明创建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; }
文本文件过滤器.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"); } }
索引器.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"); } }
数据和索引目录创建
我们使用了从 record1.txt 到 record10.txt 的 10 个文本文件,其中包含学生的姓名和其他详细信息,并将它们放在目录E:\Lucene\Data 中。 测试数据。索引目录路径应创建为E:\Lucene\Index。运行该程序后,您可以看到在该文件夹中创建的索引文件列表。
运行程序
完成源、原始数据、数据目录和索引目录的创建后,您可以继续编译并运行程序。为此,请保持 LuceneTester.Java 文件选项卡处于活动状态,并使用Eclipse IDE 中提供的“运行”选项或使用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
成功运行程序后,您的索引目录中将包含以下内容 -
Lucene - 索引操作
在本章中,我们将讨论索引的四个主要操作。这些操作在不同的时间都很有用,并且在整个软件搜索应用程序中都使用。
索引操作
以下是索引过程中常用操作的列表。
编号 | 操作及说明 |
---|---|
1 | 添加文档
此操作用于索引过程的初始阶段,以在新可用内容上创建索引。 |
2 | 更新文档
该操作用于更新索引以反映更新内容的变化。这与重新创建索引类似。 |
3 | 删除文档
此操作用于更新索引以排除不需要索引/搜索的文档。 |
4 | 字段选项
字段选项指定一种方式或控制使字段内容可搜索的方式。 |
Lucene - 搜索操作
搜索过程是Lucene提供的核心功能之一。下图说明了该过程及其用途。IndexSearcher是搜索过程的核心组件之一。
我们首先创建包含索引的目录,然后将其传递给IndexSearcher ,后者使用IndexReader打开目录。然后我们创建一个带有术语的查询,并通过将查询传递给搜索器来使用IndexSearcher进行搜索。IndexSearcher返回一个TopDocs对象,其中包含搜索详细信息以及作为搜索操作结果的Document的文档 ID 。
现在,我们将向您展示逐步方法,并使用基本示例帮助您了解索引过程。
创建一个查询解析器
QueryParser 类将用户输入的输入解析为 Lucene 可理解的格式查询。按照以下步骤创建一个 QueryParser -
步骤 1 - 创建 QueryParser 对象。
步骤 2 - 初始化使用标准分析器创建的 QueryParser 对象,该分析器具有要运行此查询的版本信息和索引名称。
QueryParser queryParser; public Searcher(String indexDirectoryPath) throws IOException { queryParser = new QueryParser(Version.LUCENE_36, LuceneConstants.CONTENTS, new StandardAnalyzer(Version.LUCENE_36)); }
创建索引搜索器
IndexSearcher 类充当搜索器索引在索引过程中创建的核心组件。按照以下步骤创建 IndexSearcher -
步骤 1 - 创建 IndexSearcher 对象。
步骤 2 - 创建一个 Lucene 目录,该目录应指向要存储索引的位置。
步骤 3 - 初始化使用索引目录创建的 IndexSearcher 对象。
IndexSearcher indexSearcher; public Searcher(String indexDirectoryPath) throws IOException { Directory indexDirectory = FSDirectory.open(new File(indexDirectoryPath)); indexSearcher = new IndexSearcher(indexDirectory); }
进行搜索
请按照以下步骤进行搜索 -
步骤 1 - 通过 QueryParser 解析搜索表达式来创建查询对象。
步骤 2 - 通过调用 IndexSearcher.search() 方法进行搜索。
Query query; 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); }
关闭索引搜索器
以下程序显示如何关闭 IndexSearcher。
public void close() throws IOException { indexSearcher.close(); }
应用示例
让我们创建一个测试 Lucene 应用程序来测试搜索过程。
步 | 描述 |
---|---|
1 | 按照Lucene - 第一个应用程序章节中的说明,在com.tutorialspoint.lucene包下创建一个名为LuceneFirstApplication的项目。您还可以使用在Lucene - 第一个应用程序章节中创建的项目来了解本章的搜索过程。 |
2 | 按照Lucene - 第一个应用程序章节中的说明创建LuceneConstants.java、TextFileFilter.java和Searcher.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; }
文本文件过滤器.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"); } }
搜索器.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(); } }
数据和索引目录创建
我们使用了 10 个名为 record1.txt 的文本文件 record10.txt 包含学生的姓名和其他详细信息,并将它们放在目录 E:\Lucene\Data 中。测试数据。索引目录路径应创建为 E:\Lucene\Index。运行Lucene - 索引过程一章中的索引程序后,您可以看到在该文件夹中创建的索引文件列表。
运行程序
完成源、原始数据、数据目录、索引目录和索引的创建后,您可以继续编译并运行程序。为此,请保持LuceneTester.Java文件选项卡处于活动状态,并使用 Eclipse IDE 中提供的“运行”选项或使用Ctrl + F11编译并运行LuceneTester 应用程序。如果您的应用程序成功运行,它将在 Eclipse IDE 的控制台中打印以下消息 -
1 documents found. Time :29 ms File: E:\Lucene\Data\record4.txt
Lucene - 查询编程
我们在前面的章节Lucene - 搜索操作中已经看到,Lucene 使用 IndexSearcher 进行搜索,并使用 QueryParser 创建的 Query 对象作为输入。在本章中,我们将讨论各种类型的查询对象以及以编程方式创建它们的不同方法。创建不同类型的查询对象可以控制要进行的搜索类型。
考虑高级搜索的情况,许多应用程序都提供高级搜索,其中为用户提供了多个选项来限制搜索结果。通过查询编程,我们可以很容易地实现同样的目的。
以下是我们将在适当时候讨论的查询类型列表。
编号 | 类别和描述 |
---|---|
1 | 术语查询
此类充当在索引过程中创建/更新索引的核心组件。 |
2 | 术语范围查询
当要搜索一系列文本术语时,使用 TermRangeQuery。 |
3 | 前缀查询
PrefixQuery 用于匹配索引以指定字符串开头的文档。 |
4 | 布尔查询
BooleanQuery 用于搜索使用AND、OR或NOT运算符进行多个查询的结果的文档。 |
5 | 短语查询
短语查询用于搜索包含特定术语序列的文档。 |
6 | 通配符查询
WildcardQuery 用于使用通配符(如“*”)搜索任何字符序列的文档,?匹配单个字符。 |
7 | 模糊查询
FuzzyQuery 用于使用模糊实现来搜索文档,这是基于编辑距离算法的近似搜索。 |
8 | 匹配所有文档查询
MatchAllDocsQuery 顾名思义匹配所有文档。 |
Lucene - 分析
在我们之前的一章中,我们已经看到 Lucene 使用IndexWriter使用分析器来分析文档,然后根据需要创建/打开/编辑索引。在本章中,我们将讨论分析过程中使用的各种类型的分析器对象和其他相关对象。了解分析过程以及分析器的工作原理将使您深入了解 Lucene 如何对文档进行索引。
以下是我们将在适当时候讨论的对象列表。
编号 | 类别和描述 |
---|---|
1 | 代币
令牌表示文档中的文本或单词及其元数据等相关详细信息(位置、起始偏移量、结束偏移量、令牌类型及其位置增量)。 |
2 | 令牌流
TokenStream是分析过程的输出,它由一系列令牌组成。它是一个抽象类。 |
3 | 分析仪
这是每种类型的分析器的抽象基类。 |
4 | 空白分析器
该分析器根据空格分割文档中的文本。 |
5 | 简单分析器
该分析器根据非字母字符拆分文档中的文本,并将文本转换为小写。 |
6 | 停止分析器
该分析器的工作原理与 SimpleAnalyzer 相同,并删除了“a”、“an”、“the”等常见单词。 |
7 | 标准分析仪
这是最复杂的分析器,能够处理姓名、电子邮件地址等。它会小写每个标记并删除常用单词和标点符号(如果有)。 |
Lucene - 排序
在本章中,我们将研究 Lucene 默认给出搜索结果的排序顺序,或者可以根据需要进行操作的排序顺序。
按相关性排序
这是 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(); }
按索引顺序排序
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(); }
应用示例
让我们创建一个测试 Lucene 应用程序来测试排序过程。
步 | 描述 |
---|---|
1 | 按照Lucene - 第一个应用程序章节中的说明,在com.tutorialspoint.lucene包下创建一个名为LuceneFirstApplication的项目。您还可以使用在Lucene - 第一个应用程序章节中创建的项目来了解本章的搜索过程。 |
2 | 按照Lucene - 第一个应用程序章节中的说明创建LuceneConstants.java和Searcher.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; }
搜索器.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(); } }
数据和索引目录创建
我们使用了从 record1.txt 到 record10.txt 的 10 个文本文件,其中包含学生的姓名和其他详细信息,并将它们放在目录E:\Lucene\Data 中。 测试数据。索引目录路径应创建为 E:\Lucene\Index。运行Lucene - 索引过程一章中的索引程序后,您可以看到在该文件夹中创建的索引文件列表。
运行程序
完成源、原始数据、数据目录、索引目录和索引的创建后,您就可以编译并运行程序了。为此,请保持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