博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
lucene quickstart-基本索引
阅读量:5768 次
发布时间:2019-06-18

本文共 6622 字,大约阅读时间需要 22 分钟。

hot3.png

    lucene是java语言实现的全文检索工具。使用lucene包括两个步骤,首先建立索引,然后对建立的索引进行检索。本文讲的是建立索引过程。

    本文及后面的文章都以磁盘文件为例,进行lucene建立索引、检索的演示。

    我们的磁盘上有一堆文件,我们可能有如下的需求:

  • 按文件名搜索文件(使用最多)

  • 按文件路径搜索文件(这个。。。)

  • 按文件类型搜索文件

  • 按文件大小搜索文件

  • 按修改日期搜索文件

  • 按文件内容搜索文件

  • ……

    想想我们人是怎么做的?

    我们拿一张纸、一支笔,填写下面的表格:

序号

文件名

文件路径

文件类型

文件大小

修改时间

内容

……

 

    填完以后,搜索的时候就可以照着这张纸“按图索骥”了。

    在lucene中,这张纸叫做Directory(也就是索引保存的目录),这支笔叫做IndexWriter,表格中一条记录叫做Document,记录中的每项叫做Field。

    OK,新建一个Indexer的类,并对外提供index(String indexDir, String... dataDirs)的方法建立索引。

    伪代码如下:

public class Indexer {    /**     * 建立索引     *      * @param indexDir     *            索引保存路径     * @param dataDirs     *            数据文件路径     * @throws Exception     */    public void index(String indexDir, String... dataDirs) throws Exception {        实例化IndexerWriter对象:IndexWriter writer = ....                for dataDir in dataDirs            建立索引:index(writer, new File(dataDir))                关闭流    }        /**     * 对文件(或目录)建立索引     *      * @param writer     *            IndexWriter对象     * @param file     *            文件或目录     */    private void index(IndexWriter writer, File file) {        如果file为目录:            对目录下的子文件(夹),调用index(writer, file)方法        如果file为文件:            生成一条Document记录,并将各项填充到该Document中,然后将该Document添加到writer    }}

    上面的伪代码不难转为Java代码。

package cn.lym.lucene.quickstart.index;import java.io.File;import java.io.FileReader;import java.io.Reader;import org.apache.log4j.LogManager;import org.apache.log4j.Logger;import org.apache.lucene.analysis.standard.StandardAnalyzer;import org.apache.lucene.document.Document;import org.apache.lucene.document.Field.Store;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.store.Directory;import org.apache.lucene.store.FSDirectory;import org.apache.lucene.util.Version;import cn.lym.lucene.quickstart.util.FileUtil;import cn.lym.lucene.quickstart.util.StreamUtil;/** * 提供对磁盘文件建立索引的功能 *  * @author liuyimin * */public class Indexer {    /**     * Logger对象     */    private static final Logger logger = LogManager.getLogger(Indexer.class);    /**     * 建立索引     *      * @param indexDir     *            索引保存路径     * @param dataDirs     *            数据文件路径     * @throws Exception     */    public void index(String indexDir, String... dataDirs) throws Exception {        Directory directory = FSDirectory.open(new File(indexDir));        IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, new StandardAnalyzer());        IndexWriter writer = new IndexWriter(directory, config);        for (String dataDir : dataDirs) {            index(writer, new File(dataDir));            writer.commit();        }        // 关闭流        StreamUtil.close(writer, directory);    }    /**     * 对文件(或目录)建立索引     *      * @param writer     *            IndexWriter对象     * @param file     *            文件或目录     */    private void index(IndexWriter writer, File file) {        if (file.isDirectory()) {// 目录,需要递归建立索引            File[] subFiles = file.listFiles();            if (subFiles != null) {                for (File subFile : subFiles) {                    index(writer, subFile);                }            }        } else if (file.isFile()) {// 文件,对文件建立索引            if (logger.isDebugEnabled()) {                logger.debug("indexing file: " + file.getAbsolutePath());            }            try {                Document document = file2Document(file);                writer.addDocument(document);            } catch (Exception e) {                logger.error(                        "An error occurred while adding a document to indexwriter. File: " + file.getAbsolutePath(), e);            }        }    }    /**     * 将文件转为lucene的{@link Document}类型
     * 其中包括:     * 
         * 
  • pathname:路径名
  •      * 
  • filename:文件名
  •      * 
  • size:文件大小(字节)
  •      * 
  • type:文件类型
  •      * 
  • content:文件内容(只有明文文件有,判断是否是明文文件:{@link FileUtil#isPlainTextFile(File)}     * )
  •      * 
     *      * @param file     * @return     */    private Document file2Document(File file) {        Document document = new Document();        document.add(new StringField("pathname", file.getAbsolutePath(), Store.YES));        document.add(new StringField("filename", file.getName(), Store.YES));        document.add(new StringField("type", FileUtil.getFileType(file), Store.YES));        document.add(new LongField("size", file.length(), Store.YES));        document.add(new LongField("lastmodified", file.lastModified(), Store.YES));        if (FileUtil.isPlainTextFile(file)) {// 对明文文件的内容建立索引            try {                Reader reader = new FileReader(file);                document.add(new TextField("content", reader));            } catch (Exception e) {                logger.error("An error occurred while indexing " + file.getAbsolutePath(), e);            }        }        return document;    }}

   使用了两个工具类。

   FileUtil.java

package cn.lym.lucene.quickstart.util;import java.io.File;/** * 文件有关的工具类 *  * @author liuyimin * */public class FileUtil {    /**     * 获得文件类型     *      * @param file     * @return     */    public static String getFileType(File file) {        String fileName = file.getName();        int index = fileName.lastIndexOf(".");        if (index != -1) {            return fileName.substring(index + 1);        }        return fileName;    }    /**     * 判断文件是否是明文的文件     *      * @param file     * @return     */    public static boolean isPlainTextFile(File file) {        // 为了简化,这里只将txt文件作为明文文件        String fileType = getFileType(file);        return "txt".equals(fileType);    }}

    StreamUtil.java

package cn.lym.lucene.quickstart.util;import java.io.Closeable;/** * 流操作有关的工具类 *  * @author liuyimin * */public class StreamUtil {    /**     * 关闭流操作     *      * @param closeables     */    public static void close(Closeable... closeables) {        if (closeables != null) {            for (Closeable closeable : closeables) {                if (closeable != null) {                    try {                        closeable.close();                    } catch (Exception e) {                    } finally {                        closeable = null;                    }                }            }        }    }}

    需要说明的几点:

  1. 关于Field。Field可控的参数包括:是否建立索引、是否保存、是否分词以及类型(数值类型或者字符类型)。

    常用的Field有下面几种:

    1. StringField:字符类型、建立索引并且不分词。存储与否可控。

    2. LongField:数值类型、建立索引并且不分词。存储与否可控。

    3. TextField:字符类型、建立索引并且分词。存储与否可控。

关于Directory。Directory为索引存放的目录,可以存放在磁盘中(例子中的就是写在磁盘中)也就是FSDirectory;也可以放在内存中,也就是RAMDirectory。

    本文的代码可以在 获取。

转载于:https://my.oschina.net/u/1466185/blog/501420

你可能感兴趣的文章
上位机和底层逻辑的解耦
查看>>
关于微信二次分享 配置标题 描述 图片??
查看>>
springcloud使用zookeeper作为config的配置中心
查看>>
hystrix实战之javanica
查看>>
校园火灾Focue-2---》洗手间的一套-》电梯
查看>>
css控制文字换行
查看>>
bzoj1913
查看>>
bzoj2301(莫比乌斯反演)
查看>>
【转】对于HttpClient和HtmlUnit的理解
查看>>
L104
查看>>
分镜头脚本
查看>>
ASP.NET中的cookie编程技术
查看>>
链表基本操作的实现(转)
查看>>
邮件发送1
查看>>
[转] libcurl异步方式使用总结(附流程图)
查看>>
编译安装LNMP
查看>>
[转]基于display:table的CSS布局
查看>>
企业级 SpringBoot 教程 (二)Spring Boot配置文件详解
查看>>
crm 02--->讲师页面及逻辑
查看>>
AS3.0 Bitmap类实现图片3D旋转效果
查看>>