什么是lucene

Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎

为什么我们要用Lucene?对比数据库

1.lucene可以对文件进行检索,这是数据库所不能的

2.对文本检索,lucene可以使用索引,检索效率高

3.lucene消耗内存少

4.lucene可以对搜索结果进行排名,进行高亮显示等。

lucene的流程

全文检索的流程分为两大部分:索引流程、搜索流程。
索引流程:采集数据—>构建文档对象—>创建索引(将文档写入索引库)。
搜索流程:创建查询—>执行搜索—>渲染搜索结果。

代码演示

基于lucene7.7

索引流程:

public class Index {

    // 写索引实例
    private IndexWriter writer;

    public Index() throws Exception {
        // 得到索引所在目录的路径,一般都用FSDirectory会根据环境选择最好的打开方式
        Directory directory = FSDirectory.open(Paths.get("/Users/temp/lucene/index"));
        // 保存用于创建IndexWriter的所有配置。会使用默认分词器
        StandardAnalyzer standardAnalyzer = new StandardAnalyzer();
        CharArraySet stopwordSet = standardAnalyzer.getStopwordSet();
        CharArraySet charArraySet = new CharArraySet(stopwordSet, true);
        boolean g32 = charArraySet.add("g32");
        System.out.println(g32);
        System.out.println(charArraySet);
        IndexWriterConfig iwConfig = new IndexWriterConfig(new StandardAnalyzer(charArraySet));
        // 实例化IndexWriter
        writer =  new IndexWriter(directory, iwConfig);
    }

    public static void main(String[] args) throws Exception {

        //被索引数据的路径
        String dataDir = "/Users/temp/lucene/data";
        Index indexer = null;
        int numIndexed = 0;
        //索引开始时间
        long start = System.currentTimeMillis();
        try {
            indexer = new Index();
            indexer.deleteAll();
            numIndexed = indexer.index(dataDir);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                indexer.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //索引结束时间
        long end = System.currentTimeMillis();
        System.out.println("索引:" + numIndexed + " 个文件 花费了" + (end - start) + " 毫秒");

    }

    public long deleteAll() throws IOException {
        return writer.deleteAll();
    }

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


    private static Document getDocument(File f) throws Exception {
        Document doc = new Document();
        //把设置好的索引加到Document里,以便在确定被索引文档
        doc.add(new TextField("contents", new FileReader(f)));
        //Field.Store.YES:在查找结果时可以还原文档,为NO不能还原文档
        doc.add(new TextField("fileName", f.getName(), Field.Store.YES));
        //把完整路径存在索引文件里
        doc.add(new TextField("fullPath", f.getCanonicalPath(), Field.Store.YES));
        return doc;
    }

    public int index(String dataDir) throws Exception {
        File[] files = new File(dataDir).listFiles();
        for (File file : files) {
            //索引指定文件
            indexFile(file);
        }
        //返回索引了多少个文件
        return  writer.getDocStats().numDocs;
    }

    public void indexFile(File f) throws Exception {
        //输出索引文件的路径
        System.out.println("索引文件:" + f.getCanonicalPath());
        //获取文档,文档里再设置每个字段
        Document doc = getDocument(f);
        //开始写入,就是把文档写进了索引文件里去了;
        writer.addDocument(doc);
    }

}

搜索流程:

public class Search {


    public static void search(String indexDir, String q) throws Exception {

        // 得到读取索引文件的路径
        Directory dir = FSDirectory.open(Paths.get(indexDir));
        // 通过dir得到的路径下的所有的文件
        IndexReader reader = DirectoryReader.open(dir);
        // 建立索引查询器
        IndexSearcher is = new IndexSearcher(reader);
        // 实例化分析器
        Analyzer analyzer = new StandardAnalyzer();
        // 建立查询解析器
        /**
         * 第一个参数是要查询的字段; 第二个参数是分析器Analyzer
         */
        QueryParser parser = new QueryParser("contents", analyzer);

        // 根据传进来的p查找
        Query query = parser.parse(q);
        // 计算索引开始时间
        long start = System.currentTimeMillis();
        // 开始查询
        /**
         * 第一个参数是通过传过来的参数来查找得到的query; 第二个参数是要出查询的行数
         */
        TopDocs hits = is.search(query, 10);
        // 计算索引结束时间
        long end = System.currentTimeMillis();
        System.out.println("匹配 " + q + " ,总共花费" + (end - start) + "毫秒" + "查询到" + hits.totalHits + "个记录");
        // 遍历hits.scoreDocs,得到scoreDoc
        /**
         * ScoreDoc:得分文档,即得到文档 scoreDocs:代表的是topDocs这个文档数组
         *
         * @throws Exception
         */
        for (ScoreDoc scoreDoc : hits.scoreDocs) {
            Document doc = is.doc(scoreDoc.doc);
            System.out.println(doc.get("fullPath"));
            System.out.println(doc.get("fileName"));
        }

        // 关闭reader
        reader.close();
    }

    public static void main(String[] args) {
        String indexDir = "/Users/temp/lucene/index";
        //我们要搜索的内容
        String q = "i love you";
        try {
            search(indexDir, q);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

其他

上面代码的lucene,只是一个基础的例子。很多其他的全文检索工具都是基于lucene在做,比如solr,elasticsearch等。

其他参考

https://mp.weixin.qq.com/s/nhyb9ZwQRJjcRDXVFK0_1w

欢迎关注公众号蜜蜂技术巢了解更多知识