Lucene 快速入门

本文介绍Lucene这一基于Java的全文检索工具包的基本原理及应用。通过示例代码详细展示了如何使用Lucene建立文档索引,并进行高效搜索。涵盖了Document、Field、Analyzer等核心组件的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lucene 简介

Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能。

Lucene 6.0.0 demo API

要想快速入门最快的学习方法就是看官方 demo 文档。

所需要的 jar 包:

lucene-core-{version}.jar
lucene-queryparser-{version}.jar
lucene-analyzers-common-{version}.jar
lucene-demo-{version}.jar

建立索引

全文搜索之所以如此的迅速就是因为搜索是在索引库中进行,将所需搜索的内容建立索引并以文件的形式保存。

Lucene 提供了五个基本类来建立索引:

Document

Document 是用来描述文档的,一个 Document 对象由多个 Field 对象组成。

Field

Field 对象是用来描述文档的某个属性的。可以把一个 Document 对象比喻成数据库中的一条记录,Field 是这个记录的字段,例如一个 File 对象的路径和文本内容可以用两个 Field 对象分别描述。

Analyzer

分词器。在一个文档被索引之前,首先需要对文档内容进行分词处理。

IndexWriter

IndexWriter 是 Lucene 用来创建索引的一个核心类,它的作用是把一个个的 Document 对象加到索引库中来。

Directory

处理索引的存储位置。


样例 IndexFiles.java 对文本文档建立索引。

  public static void main(String[] args) {
    // 索引存放目录
    String indexPath = "index";

    String docsPath = "需要索引的目录";
    final Path docDir = Paths.get(docsPath);
    Date start = new Date();
    try {
      System.out.println("Indexing to directory '" + indexPath + "'...");

      Directory dir = FSDirectory.open(Paths.get(indexPath));
      Analyzer analyzer = new StandardAnalyzer();
      IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
      IndexWriter writer = new IndexWriter(dir, iwc);

      indexDocs(writer, docDir);

      writer.close();

      Date end = new Date();
      System.out.println(end.getTime() - start.getTime() + " total milliseconds");

    } catch (IOException e) {
      System.out.println(" caught a " + e.getClass() +
          "\n with message: " + e.getMessage());
    }
  }
  /**
   * 对每个文件进行索引
   * @param writer 存储索引
   * @param path 需要索引的文件或目录
   * /
  static void indexDocs(final IndexWriter writer, Path path) throws IOException {
    // 如果是目录就遍历
    if (Files.isDirectory(path)) {
      Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
          try {
            indexDoc(writer, file, attrs.lastModifiedTime().toMillis());
          } catch (IOException ignore) {
            // 如果文件不能读取不影响下一个文件的索引
          }
          return FileVisitResult.CONTINUE;
        }
      });
    } else {
      indexDoc(writer, path, Files.getLastModifiedTime(path).toMillis());
    }
  }
  /**
   * 设置索引内容
   */
  static void indexDoc(IndexWriter writer, Path file, long lastModified) throws IOException {
    try (InputStream stream = Files.newInputStream(file)) {
      Document doc = new Document();
      // 构造器 StringField(String name, String value, Field.Store stored)
      // StringField 索引但不分词, 也就是会把这个字符串当成一个完整的词来进行索引.
      // Field.Store 是否存储
      Field pathField = new StringField("path", file.toString(), Field.Store.YES);
      doc.add(pathField);
      // 构造器 TextField(String name, Reader reader)
      // TextField 索引分词
      doc.add(new TextField("contents", new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))));
      // OpenMode.CREATE  创建新索引或覆盖已有索引
      // OpenMode.CREATE_OR_APPEND 将索引添加进已有索引, 如果不存在旧索引就创建新索引
      if (writer.getConfig().getOpenMode() == OpenMode.CREATE) {
        System.out.println("adding " + file);
        writer.addDocument(doc);
      } else {
        System.out.println("updating " + file);
        writer.updateDocument(new Term("path", file.toString()), doc);
      }
    }
  }

搜索

文本文档建立好索引后,就可以在索引上进行搜索啦。

Lucene 提供了四个基本类来进行搜索:

IndexSearch

IndexSearcher 是用来在建立好的索引上进行搜索的。它只能以只读的方式打开一个索引,所以可以有多个 IndexSearcher 的实例在一个索引上进行操作。

Query

这个类的目的是把用户输入的查询字符串封装成 Lucene 能够识别的 Query。

TopDocs

存储 IndexSearcher.search(Query,int) 返回的结果集。

ScoreDoc

将 TopDocs 数据处理成所需的 hits。


样例 SearchFiles.java 进行搜索

  public static void main(String[] args) throws Exception {
    // 索引目录
    String index = "index";
    // 要搜索的字段
    String field = "contents";
    String queries = null;
    String queryString = null;
    // 需要显示的结果数
    int hitsPerPage = 10;

    IndexReader reader = DirectoryReader.open(FSDirectory.open(Paths.get(index)));
    IndexSearcher searcher = new IndexSearcher(reader);
    Analyzer analyzer = new StandardAnalyzer();

    BufferedReader in = null;
    in = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));

    QueryParser parser = new QueryParser(field, analyzer);
    while (true) {
      if (queries == null && queryString == null) {                        // prompt the user
        System.out.println("Enter query: ");
      }

      String line = queryString != null ? queryString : in.readLine();

      if (line == null || line.length() == -1) {
        break;
      }

      line = line.trim();
      if (line.length() == 0) {
        break;
      }

      Query query = parser.parse(line);
      System.out.println("Searching for: " + query.toString(field));
      TopDocs results = searcher.search(query, hitsPerPage);
      ScoreDoc[] hits = results.scoreDocs;
      int numTotalHits = results.totalHits;
      System.out.println(numTotalHits + " total matching documents");
      for(int i=0;i<hits.length;i++){
        Document doc = searcher.doc(hits[i].doc);
        System.out.println(doc.get("path"));
      }

      if (queryString != null) {
        break;
      }
    }
    reader.close();
  }

以上是对文本内容进行搜索,如果需要搜索目录,只需修改 Document 和 Field

// 构造器 TextField(String name, String value, Field.Store store) 
doc.add(new TextField("path",file.toString(),Field.Store.YES));
String field = "path";
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值