Lucene In Action 读书笔记(一)

简介image

Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。(摘自百度百科)

代码环境

操作系统:centos 5.8

开发环境:Eclipse 4.3

构建工具:Maven 4.0

Maven配置

为了能够按照书中的例子进行学习,这里依赖的Lucene版本是3.0.1

<dependencies>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>3.0.1</version>
        </dependency>
    </dependencies>

完整配置

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.linjl.study.book</groupId>
    <artifactId>book_luceneInAction</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source />
                    <target />
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>3.0.1</version>
        </dependency>
    </dependencies>
</project>
程序示例

下面将用两个例子进行Lucene入门讲解

案例一:建立索引

案例一主要展示通过对指定路径下.txt文件建立索引的过程

完整源码:

package com.linjl.study.book.luceneInAction.chapter1;

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 indexWriter;

    public Indexer(String indexDir) throws IOException {
        //步骤一:创建 Directory
        Directory dir = FSDirectory.open(new File(indexDir));
        //步骤二:创建 IndexWriter
        indexWriter = new IndexWriter(dir, new StandardAnalyzer(
                Version.LUCENE_30), true, IndexWriter.MaxFieldLength.UNLIMITED);
    }

    public void close() throws CorruptIndexException, IOException {
        //步骤五:关闭IndexWriter
        indexWriter.close();
    }

    public int index(String dataDir, FileFilter fileFilter) throws IOException {
        File[] files = new File(dataDir).listFiles();
        for (File file : files) {
            if (!file.isDirectory() && !file.isHidden() && file.exists()
                    && file.canRead()
                    && (fileFilter == null || fileFilter.accept(file))) {
                indexFile(file);
            }
        }
        return indexWriter.numDocs();
    }

    private void indexFile(File file) throws IOException {
        System.out.println("Indexing " + file.getCanonicalPath());
        //步骤三:创建Document对象
        Document doc = getDocument(file);
        //步骤四:添加Document
        indexWriter.addDocument(doc);
    }

    protected Document getDocument(File file) throws IOException {
        Document doc = new Document();
        doc.add(new Field("contents", new FileReader(file)));
        doc.add(new Field("filename", file.getName(), Field.Store.YES,
                Field.Index.NOT_ANALYZED));
        doc.add(new Field("fullpath", file.getCanonicalPath(), Field.Store.YES,
                Field.Index.NOT_ANALYZED));
        return doc;
    }

    private static class TextFilesFilter implements FileFilter {

        public boolean accept(File pathname) {
            return pathname.getName().toLowerCase().endsWith(".txt");
        }

    }

    public static void main(String[] strs) throws IOException {
        //存放索引的位置(linux环境下路径)
        String indexDir = "/opt/test/lucene/index";
        //存放待索引文件的位置(linux环境下路径)
        String dataDir = "/opt/test/lucene/files";
        long startTime = System.currentTimeMillis();
        Indexer indexer = new Indexer(indexDir);
        int numIndexed;
        try {
            numIndexed = indexer.index(dataDir, new TextFilesFilter());
        } finally {
            indexer.close();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Indexing " + numIndexed + " files took "
                + (endTime - startTime) + "ms");
    }
}
案例二:搜索索引

案例二展示如何通过对指定的索引文件夹进行关键词索引

完整源码:

package com.linjl.study.book.luceneInAction.chapter1;

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.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 {

    public static void search(String indexDir, String searchWord)
            throws IOException, ParseException {
        //步骤一:创建Directory
        Directory dir = FSDirectory.open(new File(indexDir));
        //步骤二:创建IndexSearcher
        IndexSearcher indexSearcher = new IndexSearcher(dir);
        //步骤三:创建QueryParser
        QueryParser parser = new QueryParser(Version.LUCENE_30, "contents",
                new StandardAnalyzer(Version.LUCENE_30));
        long startTime = System.currentTimeMillis();
        //步骤四:解析生成查询对象
        Query query = parser.parse(searchWord);
        //步骤五:查询并获取查询结果(只是获取到查询结果的引用)
        TopDocs hits = indexSearcher.search(query, 30);
        long endTime = System.currentTimeMillis();
        System.out.println("Found " + hits.totalHits + "document(s) (in "
                + (endTime - startTime) + "ms) that matched query '"
                + searchWord + "':");
        for (ScoreDoc scoreDoc : hits.scoreDocs) {
            //步骤六:根据引用生成查询结果
            Document doc = indexSearcher.doc(scoreDoc.doc);
            System.out.println(doc.get("fullpath"));
        }
        //步骤七:关闭IndexSearcher
        indexSearcher.close();
    }

    public static void main(String[] args) throws IOException, ParseException {
        String indexDir = "/opt/test/lucene/index";
        String searchWord = "床";
        Searcher.search(indexDir, searchWord);
    }
理解建立索引过程的核心类
  • IndexWriter
    IndexWriter(写索引)是索引过程的核心组件。这个类负责创建新索引或者打开已有索引,以及向索引添加、删除或者更新文档的信息。他只能写入索引不能读取或者搜索索引。
  • Directory
    Directory描述了Lucene索引存放的位置。它是一个抽象类,有很多子类,例子中的FsDirectory是基于文件系统的索引,还有基于内存等更多子类。
  • Analyzer
    文本文件在被索引或者建立索引的时候都需要经过Analyzer(分析器)处理。它负责从被索引文本文件中提取语汇单元,并提出剩下的无用信息。Analyzer是一个抽象类,Lucene提供了几个实现类,不过对中文分词的效果不太好,网上有几个比较好的开源中文分词库IKAnalyzermmseg
  • Document
    Document(文档)对象代表一些域(Field)的集合。你可以将Document理解为虚拟文档—比如Web页面、E-mail信息或者文本文件---然后你可以从中取回大量的数据。
  • Field
    索引中的每个文档都包含一个或多个不同命名的域,这些鱼包含在Field类中,每个域都有一个域名和对应的域值,以及一组选项来精确控制Lucene索引操作各个域值。文档可能拥有不值一个同名的域。在这种情况下,域的值就按照索引操作顺序添加进去。在搜索时,所有域的文本就好像连接在一起,作为一个文本域来处理。
理解搜索过程的核心类
  • IndexSearcher
    IndexSearcher类用于搜索由IndexWriter类创建的索引:这个类公开了几个搜索的方法,他是链接索引的中间环节,可以将IndexSearcher类看作是一个以只读方式打开索引的类。它需要利用Direcotry实例来控制前期创建的索引,然后才能提供大量的搜索方法。该类最简单的用法如下:
    Directory dir = FSDirectory.open(new File("/tmp/index"));
    IndexSearcher searcher = new IndexSearcher(dir);
    Query q = new TermQuery(new Term("contents","lucene"));
    TopDocs hits = searcher.search(q,10);
    searcher.close();
  • Term
    Term对象是搜索功能的基本单元,与Field对象类似,Term对象包含一对字符串元素:域名和单词。
  • Query
    Lucene含有许多具体的Query(查询)子类。
  • TermQuery
    TermQuery是Lucene提供的最基本的查询类型,也是简单查询类型之一。
  • TopDocs
    TopDocs类是一个简单的指针容器,指针一般指向前N个排名的搜索结果,搜索结果即匹配查询条件的文档。TopDocs会记录前N个结果中每个结果的int docID(可以用它来回复文档)和浮点型分数
小结

本文主要是Lucene In Action 第一章的内容,通过2个例子,对lucene有了最初的认识和使用方法。

(全文完 linjl 20130904 深圳)

转载于:https://my.oschina.net/linjunlong/blog/159000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值