Lucene 基本原理(三)创建索引及搜索的Java代码实现

直观感受一下,如何使用Java代码,利用Lucene创建索引并实现全文搜索的功能。

基础知识

(1)分词器,有很多种,根据业务需要自己设定。常见的IK分词器、jieba分词器、PanGu分词器等等。

可以参考Apache Lucene(全文检索引擎)—分词器11大Java开源中文分词器的使用方法和分词效果对比做简单了解。

(2)Lucene的基本知识

  • Document:文档是建索引的基本单位,不同的文档是保存在不同的段中的,包含一个或者多个Field;
  • Field:一篇文档包含不同类型的信息,可以分开索引,比如标题,时间,正文,作者等,都可以保存在不同的Field里;
  • Term:不可分割的单词,搜索最小单元,是经过词法分析和语言处理后的字符串;
  • Token:一个Term呈现方式,包含这个Term的内容、在文档中的起始位置、类型;

先把简答功能搭建起来,其次熟练使用工具,然后深入理解原理。

创建索引

        /* INDEX_PATH指创建索引后,索引的存放位置*/            
        Directory directory = FSDirectory.open(FileSystems.getDefault().getPath(INDEX_PATH));
        /*分词器Analyzer analyzer = new StandardAnalyzer();*/
        Analyzer analyzer = new IKAnalyzer(true);
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
        /* 把需要创建索引文件放入FILE_PATH*/
        List<File> files = listFiles(FILE_PATH);
        for (int i = 0; i < files.size(); i++) {
             Document document = new Document();
             File file = files.get(i);
             document.add(new Field("content", readFile(file.getAbsolutePath()), TextField.TYPE_STORED));
             document.add(new Field("fileName", file.getName(), TextField.TYPE_STORED));
             document.add(new Field("updateTime", file.lastModified() + "", TextField.TYPE_STORED));
             indexWriter.addDocument(document);           
         }

new Field需要加入到document中,存储选项和索引选项的枚举值如下:

Field.Store.YES或者NO(存储域选项)

设置为YES表示或把这个域中的内容完全存储到文件中,方便进行文本的还原;

设置为NO表示把这个域的内容不存储到文件中,但是可以被索引,此时内容无法完全还原;

Field.Index(索引选项)

Index.ANALYZED:进行分词和索引,适用于标题、内容等;

Index.NOT_ANALYZED:进行索引,但是不进行分词,如果身份证号、姓名、ID等,适用于精确搜索;

Index.ANALYZED_NOT_NORMS:进行分词但是不存储norms信息,这个norms中包括了创建索引的时间和权值等信息;

Index.NOT_ANALYZED_NOT_NORMS:即不进行分词也不存储norms信息;

Index.NO:不进行索引;

搜索索引

            /*1、创建Directory*/
            /*INDEX_PATH 索引存放的路径*/
            Directory directory = FSDirectory.open(FileSystems.getDefault().getPath(INDEX_PATH));
            /*2、创建IndexReade*/
            DirectoryReader directoryReader = DirectoryReader.open(directory);
            /* 3、根据IndexReader创建IndexSearch*/
            IndexSearcher indexSearcher = new IndexSearcher(directoryReader);
             /*4、创建搜索的Query*/
            /*使用IK分词*/
            Analyzer analyzer = new IKAnalyzer(true);

            /*要搜索的字段,一般搜索时都不会只搜索一个字段*/
            String[] fields = {"fileName", "content"};
           
            BooleanClause.Occur[] clauses = {BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD};
            /*MultiFieldQueryParser表示多个域解析*/
            /*keyword 表示:用户搜索内容经过分词去掉停用词后的词语*/
            Query multiFieldQuery = MultiFieldQueryParser.parse(keyWord, fields, clauses, analyzer);

            /*5、根据searcher搜索并且返回TopDocs 搜索前10条结果*/
            TopDocs topDocs = indexSearcher.search(multiFieldQuery, 10);
             /*6、根据TopDocs获取ScoreDoc对象,即匹配文档的个数*/
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;

            QueryScorer scorer = new QueryScorer(multiFieldQuery, "content");
            for (ScoreDoc scoreDoc : scoreDocs) {
                /*7、根据searcher和ScoreDoc对象获取具体的Document对象*/
                Document document = indexSearcher.doc(scoreDoc.doc);
                System.out.println("-----------------------------------------");
                System.out.println(document.get("fileName") + ":" + document.get("updateTime"));
            }

搜索还可以用其他的搜索方式:分组搜索、模糊搜索等等

布尔搜索:字段之间的与或非关系,MUST表示and,MUST_NOT表示not,SHOULD表示or

注意:

搜索时容易出现以下异常,造成这个异常的主要原因是,搜索的内容包含了Lucene的关键字

org.apache.lucene.queryParser.ParseException: Encountered "<EOF>" at line 1, column 0.
Was expecting one of:
    <NOT> ...
    "+" ...
    "-" ...
    "(" ...
    <QUOTED> ...
    <TERM> ...
    <PREFIXTERM> ...
    <WILDTERM> ...
    "[" ...
    "{" ...
    <NUMBER> ...

出现特殊字符或者Lucene关键字,可以使用 QueryParser的静态方法escape(string s),进行自动转义特殊字符后再进行关键字的查询 ;或者使用反斜杠(\\)进行转义,如搜索中包含“+”,使用“\\+”进行转义

lucene的特殊字符保护了以下的字符: 

+, -, &&, || , ! , (,) , { } , [ ] , ^, " , ~, *, ?, : , \, / 。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值