• 初识Lucene


         以前听过Lucene的大名,但是实际项目中一直没机会用到。直到今天,无事看看,发现者东西真是厉害,很多知名公司都已经在用了,包括google和apple。
    这篇文章将分3部分介绍lucene, 1. Lucene简单的介绍  2.如何创建索引  3.如何搜索
     
    1. Lucene简单的介绍
     
         Lucene是一个全文检索引擎,官网是http://lucene.apache.org 当前最新版是4.4
    官网除了介绍Lucene外,还在显目位置放了Solr的东西,看介绍说是基于Lucene core的高性能搜索服务器,日后有空再去研究他。
    后来又去弄了本Lucene in action 2nd, 准备走走经典流程Hello World。
         和预想的一样,搜索引擎,逃脱不了这样的套路:
         创建索引的时候
         用web爬虫等数据内容获取工具拿到数据    接着    将内容进行分词处理,留下有意义的词    然后创建索引保存起来
         在搜索的时候
         得到用户的搜索词,解析分词,找到索引文件,搜索,返回搜索结果。
         Lucene in action中是这样描述的:
     
         大体是相同的,从资料中获取数据,构造文档,分析文档进行分词,然后生成索引文档,然后保存。当搜索的时候,用户通过搜索UI输入关键字,应用程序创建搜索对象,搜索索引,然后返回结果。
         
         接下来,我们先走一遍Hello World,再介绍下各个重要部分。
     
    2. 创建索引
         下面是创建索引的代码:
         
    /**
     * 
     */
    package demo;

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileFilter;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;

    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.document.Field;
    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.store.Directory;
    import org.apache.lucene.store.FSDirectory;
    import org.apache.lucene.util.Version;

    /**
     * @author 
     * 
     */
    publicclass Indexer {
    private IndexWriter writer;

    /**
    *
    * @param indexDir
    * @throws IOException
    */
    public Indexer(String indexDir) throws IOException {
    // 定义索引的存放目录为File System
    Directory dir = FSDirectory.open(new File(indexDir));
    // 配置创建创建方式,使用标准的Analyzer
    IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_44,
    new StandardAnalyzer(Version.LUCENE_44));
    writer = new IndexWriter(dir, conf);
    }

    publicint index(String dataDir, FileFilter filter) throws Exception {
    // 遍历数据目录
    File[] files = new File(dataDir).listFiles();
    for (File f : files) {
    if (!f.isDirectory() && !f.isHidden() && f.exists() && f.canRead() && (filter == null || filter.accept(f))) { // 得到符合条件的txt文件 indexFile(f); }
    }
    return writer.numDocs();
    }
    privatevoid indexFile(File f) throws Exception {
    System.out.println("Indexing " + f.getCanonicalPath());
    Document doc = getDocument(f);
    writer.addDocument(doc);
    }
    // 为Document 添加 Field
    protected Document getDocument(File f) throws Exception {
    Document doc = new Document();
    doc.add(new TextField("content", new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"))));
    doc.add(new StringField("filename", f.getName(), Field.Store.YES));
    doc.add(new StringField("fullpath", f.getCanonicalPath(),
    Field.Store.YES));
    return doc;
    }
    /**
    * @throws IOException
    */
    publicvoid close() throws IOException {
    writer.close();
    }
    // 过滤文件 privatestaticclass TextFilesFilter implements FileFilter {
    publicboolean accept(File path) {
    return path.getName().toLowerCase().endsWith(".txt");
    }
    }
    /**
    * @param args
    * @throws Exception
    */
    publicstaticvoid main(String[] args) throws Exception {
    // 索引存放路径
    String indexDir = "/Users/apple/Documents/index";
    // 数据文件路径
    String dataDir = "/Users/apple/Documents/data";
    long start = System.currentTimeMillis();
    Indexer indexer = new Indexer(indexDir);
    int numIndexed;
    try {
    // 调用自己写得index方法创建索引
    numIndexed = indexer.index(dataDir, new TextFilesFilter());
    } finally {
    indexer.close();
    }
    long end = System.currentTimeMillis();
    System.out.println("Indexing " + numIndexed + " files took " + (end - start) + " milliseconds");
    }
    }
     
         这段代码是这样:
         
         首先定义了数据存放目录,以及索引目录,后者空,前者包含几个txt文档,文档里面有几句英文句子(当然支持中文,但代码会复杂,不在hello world范畴了)
         定义了2个目录后,接下来就是读取文档,获取内容了,这一步大家可以按照自己的方法写,只要能够遍历txt文档,并取得内容即可。
         
    接着,
    这2个方法是把File对象创建成Document,也就是把内容存入到Document中,然后添加到IndexWriter中。一个Document对象包含若干个Field。你可以这么理解:一个Document对象想象成数据库表中得一行,而Field就是某列。
    说到IndexWriter,她是这样创建的:
    StandardAnalyzer,按照字面理解是标准分词解析器,按照我的猜想,如果要解析中文,估计也是在这里动手脚。她帮助IndexWriter解析你传进来的Field的内容,进行分词,词加权等操作。IndexWriter负责将生成的索引写入到FSDirectory中。也可以是RAM,你可以修改38行的代码。
    这样,一个索引的创建过程就完成了。如果你的代码报错,尤其是StandardAnalyzer找不到,你需要导入Analyzer / common包下的那个jar包。
    运行一遍,即可在index目录下生成索引了:
     
     
    3. 搜索
         有了索引后,就是搜索了,搜索相对简单些,构造搜索对象,然后搜索并显示结果。
     
    这个是她的运行结果
     
    至于那个为什么是null,Lucene in action没说,按照我的猜测,因为她是一个TextField对象,从文本读取出来的,她可能很大很大,如果把这个内容也放入索引,那么索引库的体积将会非常大,所以默认是不保存TextField,至于我的猜想是否正确,需待深入了解。热心的网友也可给我留言。
     
     
    就这样,一个Hello World就完成了。
     
    总结:
    创建索引的核心类:IndexWriter,Directory,Analyzer,Document,Field
     
    IndexWriter是创建索引的核心组件,她负责创建一个新索引货打开已经存在的索引,以及添加,删除更新索引中得文档。她是负责写索引的,所以也要给他指定一个Directory,告诉她索引存哪。
     
    Directory代表了Lucene 索引的存放地址,她又多种方式可用存,File System, RAM等
     
    Analyzer,在文本被索引前,将会被Analyzer处理。做分词处理,去掉一些无意义的词,如空格,停顿,the,之类的词。有多种Analyzer,自由选择以解析富文本对象等。
     
    Document,代表field的集合。可被认为是web page,email message,数据表某一行,而field就是元数据了,比如标题,内容,创建时间,路径等等,自由自定。不过你要记住的是,Lucene只能处理文本和数字。所以你要利用各种方法先将非文本转成文本。
     
    Field就是Lucene将要索引的值
     
    搜索的关键对象:
    IndexSearcher,负责搜索INdexWriter写得索引。

    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,是搜索的基本单元,与Field对象类似。包含用于搜索的Field name和value
    Query,搜索对象,和JDBC中得Query功能一样,Lucene有很多实现方式,例子中用到的是TermQuery
    TermQuery基本的搜索方式
    TopDoc,也就是搜索结果,她包含一个docID,你可以通过她取得document对象。 
  • 相关阅读:
    观察者模式
    简单工厂
    一个数组先按值排序,如果它的值有相同,就再按键排序(转)
    Python 一些好玩的函数
    python 一些基础知识
    python3 写CSV文件多一个空行的解决办法
    pandas学习笔记
    pycharm2017.1破解方法
    python的Debug调试
    python中字典的陷阱
  • 原文地址:https://www.cnblogs.com/dycg/p/3211076.html
Copyright © 2020-2023  润新知