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

或者,如果您使用集成开发环境(IDE),如Borland JBuilder、Eclipse、IntelliJ IDEA或Sun ONE Studio,请编译并运行一个简单的程序以确认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

成功启动后,应显示以下结果:

Eclipse Home page

步骤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中为您提供如下所示的目录结构。

Lucene Directories

您将在C:\lucene-3.6.2目录中找到所有Lucene库。确保您正确地在此目录上设置CLASSPATH变量,否则,在运行应用程序时将遇到问题。如果您使用的是Eclipse,则不需要设置CLASSPATH,因为所有设置都将通过Eclipse完成。

完成最后一步后,您就可以继续进行第一个Lucene示例,您将在下一章中看到。

Lucene - 第一个应用程序

在本章中,我们将学习使用Lucene框架进行实际编程。在开始使用Lucene框架编写您的第一个示例之前,您必须确保已正确设置Lucene环境,如Lucene - 环境搭建教程中所述。建议您了解Eclipse IDE的工作知识。

现在让我们继续编写一个简单的搜索应用程序,该应用程序将打印找到的搜索结果数量。我们还将看到在此过程中创建的索引列表。

步骤1 - 创建Java项目

第一步是使用Eclipse IDE创建一个简单的Java项目。选择文件 > 新建 > 项目选项,最后从向导列表中选择Java项目向导。现在使用向导窗口将您的项目命名为LuceneFirstApplication,如下所示:

Create Project Wizard

成功创建项目后,您的项目资源管理器中将包含以下内容:

Lucene First Application Directories

步骤2 - 添加所需的库

现在让我们在项目中添加Lucene核心框架库。为此,右键单击您的项目名称LuceneFirstApplication,然后按照上下文菜单中提供的以下选项操作:构建路径 > 配置构建路径,以显示Java构建路径窗口,如下所示:

Java Build Path

现在使用选项卡下提供的添加外部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;
}

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();
   }
}

Searcher.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 - 数据和索引目录创建

我们使用了10个文本文件(从record1.txt到record10.txt),其中包含学生姓名和其他详细信息,并将它们放在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 Index Directory

Lucene - 索引类

索引过程是Lucene提供的核心功能之一。下图说明了索引过程和类的使用。IndexWriter是索引过程中最重要和最核心的组件。

Indexing Process

我们将包含字段(Field)文档(Document)添加到IndexWriter中,IndexWriter使用分析器(Analyzer)分析文档(Document),然后根据需要创建/打开/编辑索引,并将它们存储/更新到目录(Directory)中。IndexWriter用于更新或创建索引,不用于读取索引。

索引类

以下是索引过程中常用的一些类。

序号 类与描述
1 IndexWriter

此类是核心组件,在索引过程中创建/更新索引。

2 Directory

此类表示索引的存储位置。

3 Analyzer

此类负责分析文档并从要索引的文本中获取标记/单词。如果没有进行分析,IndexWriter就无法创建索引。

4 Document

此类表示一个虚拟文档,其中包含字段(Field),字段是一个对象,可以包含物理文档的内容、元数据等。只有分析器(Analyzer)才能理解Document。

5 Field

这是索引过程的最小单位或起点。它表示键值对关系,其中键用于标识要索引的值。例如,一个用于表示文档内容的字段,其键为“contents”,值可能包含文档文本或数值内容的一部分或全部。Lucene只能索引文本或数值内容。

Lucene - 搜索类

搜索过程也是Lucene提供的核心功能之一。其流程与索引过程类似。Lucene的基本搜索可以使用以下类进行,这些类也可以被称为所有搜索相关操作的基础类。

搜索类

以下是搜索过程中常用的一些类。

序号 类与描述
1 IndexSearcher

此类是核心组件,读取/搜索索引过程结束后创建的索引。它接收指向包含索引的位置的目录实例。

2 Term

此类是搜索的最小单位。它类似于索引过程中的Field。

3 Query

Query是一个抽象类,包含各种实用方法,是Lucene在搜索过程中使用所有类型查询的父类。

4 TermQuery

TermQuery是最常用的查询对象,也是Lucene可以使用的许多复杂查询的基础。

5 TopDocs

TopDocs指向与搜索条件匹配的前N个搜索结果。它是一个简单的容器,包含指向文档的指针,这些文档是搜索结果的输出。

Lucene - 索引过程

索引过程是Lucene提供的核心功能之一。下图说明了索引过程和类的使用。IndexWriter是索引过程中最重要的核心组件。

Indexing Process

我们将包含字段(Field)文档(Document)添加到IndexWriter中,IndexWriter使用分析器(Analyzer)分析文档,然后创建/打开/编辑索引,并将它们存储/更新到目录(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类是核心组件,在索引过程中创建/更新索引。请按照以下步骤创建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

Lucene - 第一个应用程序章节所述,在com.tutorialspoint.lucene包下创建一个名为LuceneFirstApplication的项目。您也可以使用Lucene - 第一个应用程序章节中创建的项目来理解索引过程。

2

Lucene - 第一个应用程序章节所述,创建LuceneConstants.java,TextFileFilter.javaIndexer.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");		
   }
}

数据和索引目录创建

我们使用了10个文本文件,从record1.txt到record10.txt,包含学生姓名和其他详细信息,并将它们放在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 Index Directory

Lucene - 索引操作

在本节中,我们将讨论索引的四个主要操作。这些操作在不同时间非常有用,并在整个软件搜索应用程序中使用。

索引操作

以下是索引过程中常用的一些操作。

序号 操作与描述
1 添加文档

此操作用于索引过程的初始阶段,以对新可用内容创建索引。

2 更新文档

此操作用于更新索引以反映更新内容中的更改。它类似于重新创建索引。

3 删除文档

此操作用于更新索引以排除不需要索引/搜索的文档。

4 字段选项

字段选项指定一种方式或控制字段内容的可搜索方式。

Lucene - 搜索操作

搜索过程是Lucene提供的核心功能之一。下图说明了该过程及其使用。IndexSearcher是搜索过程的核心组件之一。

Searching Process

我们首先创建包含索引目录(Directory),然后将其传递给IndexSearcherIndexSearcher使用IndexReader打开目录。然后,我们使用Term创建一个Query,并通过将Query传递给搜索器来使用IndexSearcher进行搜索。IndexSearcher返回一个TopDocs对象,该对象包含搜索详细信息以及作为搜索操作结果的Document的文档ID。

我们现在将向您展示一种分步方法,并帮助您使用基本示例来理解索引过程。

创建一个QueryParser

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类是核心组件,搜索在索引过程中创建的索引。请按照以下步骤创建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解析搜索表达式来创建Query对象。

步骤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

以下程序显示如何关闭IndexSearcher。

public void close() throws IOException {
   indexSearcher.close();
}

示例应用程序

让我们创建一个测试Lucene应用程序来测试搜索过程。

步骤 描述
1

Lucene - 第一个应用程序章节所述,在com.tutorialspoint.lucene包下创建一个名为LuceneFirstApplication的项目。您也可以使用Lucene - 第一个应用程序章节中创建的项目来理解搜索过程。

2

Lucene - 第一个应用程序章节所述,创建LuceneConstants.java,TextFileFilter.javaSearcher.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");
   }
}

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();
   }	
}

数据和索引目录创建

我们使用了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对象作为输入。在本节中,我们将讨论各种类型的Query对象以及以编程方式创建它们的不同方法。创建不同类型的Query对象可以控制要进行的搜索类型。

考虑许多应用程序提供的“高级搜索”案例,其中为用户提供了多个选项来限制搜索结果。通过Query编程,我们可以很容易地实现这一点。

以下是我们将陆续讨论的Query类型列表。

序号 类与描述
1 TermQuery

此类是核心组件,在索引过程中创建/更新索引。

2 TermRangeQuery

当需要搜索一定范围的文本术语时,使用TermRangeQuery。

3 PrefixQuery

PrefixQuery用于匹配索引以指定字符串开头的文档。

4 BooleanQuery

BooleanQuery用于搜索多个查询的结果文档,使用AND、ORNOT运算符。

5 PhraseQuery

Phrase query用于搜索包含特定术语序列的文档。

6 WildCardQuery

WildcardQuery用于使用通配符进行搜索,例如'*'代表任何字符序列,'?'匹配单个字符。

7 FuzzyQuery

FuzzyQuery用于使用模糊实现进行搜索,这是一种基于编辑距离算法的近似搜索。

8 MatchAllDocsQuery

顾名思义,MatchAllDocsQuery匹配所有文档。

Lucene - 分析

在我们之前的章节中,我们已经看到Lucene使用IndexWriter通过Analyzer分析Document(s),然后根据需要创建/打开/编辑索引。在本节中,我们将讨论分析过程中使用的各种类型的Analyzer对象和其他相关对象。了解分析过程和分析器的运行方式将使您深入了解Lucene如何索引文档。

以下是我们将陆续讨论的对象列表。

序号 类与描述
1 Token

Token表示文档中的文本或单词,以及相关详细信息,例如其元数据(位置、起始偏移量、结束偏移量、标记类型及其位置增量)。

2 TokenStream

TokenStream是分析过程的输出,它包含一系列标记。它是一个抽象类。

3 Analyzer

这是每种类型的Analyzer的抽象基类。

4 WhitespaceAnalyzer

此分析器根据空格拆分文档中的文本。

5 SimpleAnalyzer

此分析器根据非字母字符拆分文档中的文本,并将文本转换为小写。

6 StopAnalyzer

此分析器的工作方式与SimpleAnalyzer相同,并删除常用词,例如'a'、'an'、'the'等。

7 StandardAnalyzer

这是最复杂的分析器,能够处理姓名、电子邮件地址等。它将每个标记转换为小写,并删除任何常用词和标点符号。

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.javaSearcher.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;
}

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();
   }
}

数据和索引目录创建

我们使用了10个文本文件,从record1.txt到record10.txt,其中包含学生姓名和其他详细信息,并将它们放在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
广告