您的位置:首页 > 编程语言 > Java开发

Lucene入门教程(一)

2014-06-22 15:52 423 查看
Lucene 4.5,document详解,例子实现,方法重写。

在这里分享一下Lucene的学习,主要参考官网上的一下教程和PDF版的《Lucene In Action》。当然,博客中很多内容都是摘自上面两个地方。

1. 什么是Lucene

        Lucene是一个高性能的、可扩展的信息检索工具。你可以把它融入到应用程序中以增加索引和搜索功能。Lucene是一个纯Java实现的成熟、自由、开源的软件项目。

它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。

官方网站:http://lucene.apache.org/

CSDN下载地址:http://download.csdn.net/detail/jolingogo/6472385

2. 索引和搜索

        使用Lucene,需要理解索引和搜索这两个概念。

索引:为了快速搜索大量文本文件,首先必须为文件建立索引,就像为一本书建立目录,然后把文本转换成你能够快速搜索到的格式,

而不是使用那种慢速顺序扫描的处理法。这个转换过程就叫做索引操作(indexing),他的输出就称为索引文件(index)。

        可以把索引想象成一种数据结构,这种数据结构允许对存储在其中的单词进行快速随机存取。

搜索:是在一个索引中查找关键字的过程,这个过程的目的是为了找到这些关键字在哪些地方出现过。

        搜索的质量通常有查确率(precise)和查全率(recall)来衡量。查全率可以衡量这个搜索系统查找到相关文档的能力,

而查确率则是用来衡量搜索系统过滤非相关文档的能力。

3. 第一个示例

准备工作:

1.新建2个文件夹



Lucene_data 里面,我新建了几个txt文本文件

Lucene_index用来存放索引



2. pom.xml

[html]
view plaincopy

<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>org.ygy</groupId>
<artifactId>lucene</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>lucene</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>

<!-- Lucene依赖包 -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.5.1</version>
</dependency>

<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-icu</artifactId>
<version>4.5.1</version>
</dependency>

<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>4.5.1</version>
</dependency>

</dependencies>
</project>


3.1 建立索引

[java]
view plaincopy

package org.ygy.lucene;  
  
import java.io.BufferedReader;  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.FileNotFoundException;  
import java.io.IOException;  
import java.io.InputStreamReader;  
import java.util.Date;  
  
import org.apache.lucene.analysis.Analyzer;  
import org.apache.lucene.analysis.standard.StandardAnalyzer;  
import org.apache.lucene.document.Document;  
import org.apache.lucene.document.Field;  
import org.apache.lucene.document.LongField;  
import org.apache.lucene.document.StringField;  
import org.apache.lucene.document.TextField;  
import org.apache.lucene.index.IndexWriter;  
import org.apache.lucene.index.IndexWriterConfig;  
import org.apache.lucene.index.Term;  
import org.apache.lucene.store.Directory;  
import org.apache.lucene.store.FSDirectory;  
import org.apache.lucene.util.Version;  
  
/** 
 * 建立索引 
 *  
 * @author yuguiyang 
 *  
 */  
public class IndexFiles {  
  
    // -index F:\Lucene_index -docs F:\Lucene_data  
    public static void main(String[] args) {  
        String usage = "java org.apache.lucene.demo.IndexFiles [-index INDEX_PATH] [-docs DOCS_PATH] [-update]\n\nThis indexes the documents in DOCS_PATH, creating a Lucene indexin INDEX_PATH that can be searched with SearchFiles";  
  
        String indexPath = "index"; // 索引存放的路径  
        String docsPath = null; // 需要给哪些文件建立索引(即资源库的地址)  
        boolean create = true; // 是否新建索引  
        for (int i = 0; i < args.length; i++) {  
            if ("-index".equals(args[i])) {  
                indexPath = args[(i + 1)];  
                i++;  
            } else if ("-docs".equals(args[i])) {  
                docsPath = args[(i + 1)];  
                i++;  
            } else if ("-update".equals(args[i])) {  
                create = false;  
            }  
        }  
  
        if (docsPath == null) {  
            System.err.println("Usage: " + usage);  
            System.exit(1);  
        }  
  
        // 验证资源文件地址  
        File docDir = new File(docsPath);  
        if ((!docDir.exists()) || (!docDir.canRead())) {  
            System.out.println("Document directory '" + docDir.getAbsolutePath()  
                    + "' does not exist or is not readable, please check the path");  
            System.exit(1);  
        }  
  
        // 开始建立索引  
        Date start = new Date();  
        try {  
            System.out.println("Indexing to directory '" + indexPath + "'...");  
  
            // 根据索引存放地址,创建目录  
            Directory dir = FSDirectory.open(new File(indexPath));  
            // 初始化分析器  
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45);  
            //索引配置  
            IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_45, analyzer);  
  
            if (create) {  
                iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);  
            } else {  
                iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);  
            }  
  
            //初始化索引  
            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());  
        }  
    }  
  
    //递归的方式,遍历每一个文件  
    static void indexDocs(IndexWriter writer, File file) throws IOException {  
        if (file.canRead())  
            if (file.isDirectory()) {  
                String[] files = file.list();  
  
                if (files != null)  
                    for (int i = 0; i < files.length; i++)  
                        indexDocs(writer, new File(file, files[i]));  
            } else {  
                FileInputStream fis;  
                try {  
                    fis = new FileInputStream(file);  
                } catch (FileNotFoundException fnfe) {  
                    return;  
                }  
  
                try {  
                    Document doc = new Document();  
  
                    Field pathField = new StringField("path", file.getPath(), Field.Store.YES);  
                    doc.add(pathField);  
  
                    doc.add(new LongField("modified", file.lastModified(), Field.Store.NO));  
  
                    doc.add(new TextField("contents", new BufferedReader(new InputStreamReader(fis, "UTF-8"))));  
  
                    if (writer.getConfig().getOpenMode() == IndexWriterConfig.OpenMode.CREATE) {  
                        System.out.println("adding " + file);  
                        writer.addDocument(doc);  
                    } else {  
                        System.out.println("updating " + file);  
                        writer.updateDocument(new Term("path", file.getPath()), doc);  
                    }  
                } finally {  
                    fis.close();  
                }  
            }  
    }  
}  

好了,虽然,上面的代码还不是很明白,但是,运行一下先。
运行时,需要指定一些参数:



运行结果:



好了,索引建立成功了,看一下,F:\Lucene_index文件夹



这些文件具体是什么,不太清楚,暂且当做是索引文件吧。

3.2 搜索

[java]
view plaincopy

package org.ygy.lucene;  
  
import java.io.BufferedReader;  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.IOException;  
import java.io.InputStreamReader;  
import java.util.Date;  
  
import org.apache.lucene.analysis.Analyzer;  
import org.apache.lucene.analysis.standard.StandardAnalyzer;  
import org.apache.lucene.document.Document;  
import org.apache.lucene.index.DirectoryReader;  
import org.apache.lucene.index.IndexReader;  
import org.apache.lucene.queryparser.classic.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.FSDirectory;  
import org.apache.lucene.util.Version;  
  
public class SearchFiles {  
      
    public static void main(String[] args) throws Exception {  
        //对参数的一些处理  
        String usage = "Usage:\tjava org.apache.lucene.demo.SearchFiles [-index dir] [-field f] [-repeat n] [-queries file] [-query string] [-raw] [-paging hitsPerPage]\n\nSee http://lucene.apache.org/core/4_1_0/demo/ for details.";  
  
        if ((args.length > 0) && (("-h".equals(args[0])) || ("-help".equals(args[0])))) {  
            System.out.println(usage);  
            System.exit(0);  
        }  
  
        String index = "index";  
        String field = "contents";  
        String queries = null;  
        int repeat = 0;  
        boolean raw = false;  
        String queryString = null;  
        int hitsPerPage = 10;  
  
        for (int i = 0; i < args.length; i++) {  
            if ("-index".equals(args[i])) {  
                index = args[(i + 1)];  
                i++;  
            } else if ("-field".equals(args[i])) {  
                field = args[(i + 1)];  
                i++;  
            } else if ("-queries".equals(args[i])) {  
                queries = args[(i + 1)];  
                i++;  
            } else if ("-query".equals(args[i])) {  
                queryString = args[(i + 1)];  
                i++;  
            } else if ("-repeat".equals(args[i])) {  
                repeat = Integer.parseInt(args[(i + 1)]);  
                i++;  
            } else if ("-raw".equals(args[i])) {  
                raw = true;  
            } else if ("-paging".equals(args[i])) {  
                hitsPerPage = Integer.parseInt(args[(i + 1)]);  
                if (hitsPerPage <= 0) {  
                    System.err.println("There must be at least 1 hit per page.");  
                    System.exit(1);  
                }  
                i++;  
            }  
        }  
          
        //读取索引  
        IndexReader reader = DirectoryReader.open(FSDirectory.open(new File(index)));  
        //查询索引  
        IndexSearcher searcher = new IndexSearcher(reader);  
        //分析器  
        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45);  
  
        BufferedReader in = null;  
        if (queries != null)  
            in = new BufferedReader(new InputStreamReader(new FileInputStream(queries), "UTF-8"));  
        else {  
            in = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));  
        }  
        //解析器  
        QueryParser parser = new QueryParser(Version.LUCENE_45, field, analyzer);  
        while (true) {  
            if ((queries == null) && (queryString == null)) {  
                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));  
  
            if (repeat > 0) {  
                Date start = new Date();  
                for (int i = 0; i < repeat; i++) {  
                    searcher.search(query, null, 100);  
                }  
                Date end = new Date();  
                System.out.println("Time: " + (end.getTime() - start.getTime()) + "ms");  
            }  
  
            doPagingSearch(in, searcher, query, hitsPerPage, raw, (queries == null) && (queryString == null));  
  
            if (queryString != null) {  
                break;  
            }  
        }  
        reader.close();  
    }  
  
    public static void doPagingSearch(BufferedReader in, IndexSearcher searcher, Query query, int hitsPerPage,  
            boolean raw, boolean interactive) throws IOException {  
        TopDocs results = searcher.search(query, 5 * hitsPerPage);  
        ScoreDoc[] hits = results.scoreDocs;  
  
        int numTotalHits = results.totalHits;  
        System.out.println(numTotalHits + " total matching documents");  
  
        int start = 0;  
        int end = Math.min(numTotalHits, hitsPerPage);  
        while (true) {  
            if (end > hits.length) {  
                System.out.println("Only results 1 - " + hits.length + " of " + numTotalHits  
                        + " total matching documents collected.");  
                System.out.println("Collect more (y/n) ?");  
                String line = in.readLine();  
                if ((line.length() == 0) || (line.charAt(0) == 'n')) {  
                    break;  
                }  
                hits = searcher.search(query, numTotalHits).scoreDocs;  
            }  
  
            end = Math.min(hits.length, start + hitsPerPage);  
  
            for (int i = start; i < end; i++) {  
                if (raw) {  
                    System.out.println("doc=" + hits[i].doc + " score=" + hits[i].score);  
                } else {  
                    Document doc = searcher.doc(hits[i].doc);  
                    String path = doc.get("path");  
                    if (path != null) {  
                        System.out.println(i + 1 + ". " + path);  
                        String title = doc.get("title");  
                        if (title != null)  
                            System.out.println("   Title: " + doc.get("title"));  
                    } else {  
                        System.out.println(i + 1 + ". " + "No path for this document");  
                    }  
                }  
            }  
  
            if ((!interactive) || (end == 0)) {  
                break;  
            }  
            if (numTotalHits >= end) {  
                boolean quit = false;  
                while (true) {  
                    System.out.print("Press ");  
                    if (start - hitsPerPage >= 0) {  
                        System.out.print("(p)revious page, ");  
                    }  
                    if (start + hitsPerPage < numTotalHits) {  
                        System.out.print("(n)ext page, ");  
                    }  
                    System.out.println("(q)uit or enter number to jump to a page.");  
  
                    String line = in.readLine();  
                    if ((line.length() == 0) || (line.charAt(0) == 'q')) {  
                        quit = true;  
                        break;  
                    }  
                    if (line.charAt(0) == 'p') {  
                        start = Math.max(0, start - hitsPerPage);  
                        break;  
                    }  
                    if (line.charAt(0) == 'n') {  
                        if (start + hitsPerPage >= numTotalHits)  
                            break;  
                        start += hitsPerPage;  
                        break;  
                    }  
  
                    int page = Integer.parseInt(line);  
                    if ((page - 1) * hitsPerPage < numTotalHits) {  
                        start = (page - 1) * hitsPerPage;  
                        break;  
                    }  
                    System.out.println("No such page");  
                }  
  
                if (quit)  
                    break;  
                end = Math.min(numTotalHits, start + hitsPerPage);  
            }  
        }  
    }  
}  

哎,到目前为止,对上面的程序还不是很理解,但是可以跑通了,还不错,接着学习一下。



运行后,会提示,让你输入要查找的内容:



好了,目前之理解了这么多,先学一会儿,再接着分享哈。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java lucene