lucene全文检索

浪尽此生 提交于 2019-11-30 13:23:50

 

什么是全文检索

 

将数据分为两类,

结构化数据和非结构化数据

 

结构化数据:

有固定格式和有限长度, 比如关系型数据库中的数据,

查询的方式: sql

在数据量特别大的时候,可以考虑使用全文检索技术

 

 

非结构化数据:

没有固定格式和没有规定长度,比如电脑上的文档:txt,word

查询方式: 对于少量数据可以肉眼查找

对于大量数据可以使用全文检索技术

 

 

二.什么是全文检索技术

 

全文检索: 先建立索引,再对索引进行搜索的过程就叫做全文检索技术

 

三. 全文检索适用场景

 

分为三种情形

  1. 搜索引擎:   谷歌  百度   360   搜狗   搜搜

 

  1. 站内搜索:   网站内部进行搜索,如京东,淘宝,天涯,微博,猫扑

 

 

  1. 垂直搜索:   视屏网站的搜索,比如在优酷中可以搜索到腾讯的视频

 

 

四. 如何实现全文检索

在这里可以使用lucene进行实现

 

五. 什么是lucene?

 

lucene 是apache提供用来实现全文检索的一套类库,jar,并不是框架

 

需要使用的坐标

第一步:导入jar

   必须的包:lucene-core-4.10.3.jar

             lucene-analyzers-common-4.10.3.jar  分词器

 

              commons-io.jar

              junit.jar

 

   <dependency>

            <groupId>org.apache.lucene</groupId>

            <artifactId>lucene-analyzers-common</artifactId>

            <version>4.10.3</version>

        </dependency>

 

        <dependency>

            <groupId>commons-io</groupId>

            <artifactId>commons-io</artifactId>

            <version>2.6</version>

        </dependency>

 

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.12</version>

        </dependency>

 

 

六. lucene创建索引

 

创建索引,三步

  1. 获取原始文档

 

  1. 构建索引文档对象

 

 

  1. 分析文档(分词)

 

  1. 创建索引

分词示例:

分词:spring.txt

The Spring Framework provides a comprehensive programming and configuration model.

         1、去除所有标点符号

         2、把所有大写改成小写

         3、根据空格分词

 

         4、去除停用词

         fileName:spring

         fileName:txt

         fileContent:spring

         fileContent:framework

         fileContent:provides

         fileContent:comprehensive

         fileContent:programming

         fileContent:configuration

         fileContent:model

 

以上数据就是在索引库中存储讲的最小单元:term包含域名和关键字

 

代码示例

public static void createIndex() throws IOException {
        /*
         * 实现步骤分析
         *   1. 创建一个java工程,并且导入依赖
         *   2. 创建一个indexwriter对象
         *       2.1 指定索引库的存放位置Directory对象
         *       2.2 指定一个分析器,对文档内容进行分析
         *   3. 创建document对象
         *   4. 创建field对象,将field添加到document对象中
         *   5. 使用indexwriter对象将document对象写入索引库,此过程进行索引创建,并将索引和document对象写入索引库
         *   6. 关闭indexwirter对象
         * */
  
//                 *   1. 创建一个java工程,并且导入依赖
//                *   2. 创建一个indexwriter对象
//                *       2.1 指定索引库的存放位置Directory对象
        Directory directory= FSDirectory.open(new File("D:\\Documents\\Downloads\\day02_lucene\\索引存放位置"));
  //                *       2.2 指定一个分析器,对文档内容进行分析  标准分析器
        Analyzer analyzer=new IKAnalyzer();
                            //2.3 将标准分析器对象封装到分析器对象中
                            //    两个参数: 1. lucene的版本信息 Version.LATEST,表示最新的版本
                                        //   2. 分析器对象
        IndexWriterConfig indexWriterConfig=new IndexWriterConfig(Version.LATEST,analyzer);
        IndexWriter indexWriter=new IndexWriter(directory,indexWriterConfig);
  
        indexWriter.deleteAll();
        File file=new File("D:\\Documents\\Downloads\\day02_lucene\\资料\\上课用的查询资料searchsource");
        File[] files = file.listFiles();
        for (File file1 : files) {
            //小插曲,将遍历到的文件对象封装成字符串对象,和Long对象
            String fileContent= FileUtils.readFileToString(file1);
            String filePath=file1.getPath();
  
            String fileName=file1.getName();
  
            Long fileSize=file1.length();
  //                *   3. 创建document对象
            Document document=new Document();
  //                *   4. 创建field对象,将field添加到document对象中
                    //field.store.Yes  表示将文本内容写入索引文件中
            //TextField 和 StringField的区别:textfield会被分割为很多关键字
            Field fileContentField=new TextField("filecontent",fileContent,Field.Store.YES);
            Field filePathField=new StringField("filepath",filePath,Field.Store.YES);
            Field fileNameField=new TextField("filename",filePath,Field.Store.YES);
            Field filesizeField=new LongField("filesize",fileSize,Field.Store.YES);
  
            document.add(fileContentField);
            document.add(filePathField);
            document.add(fileNameField);
            document.add(filesizeField);
  //                *   5. 使用indexwriter对象将document对象写入索引库,此过程进行索引创建,并将索引和document对象写入索引库
            indexWriter.addDocument(document);
        }
  //                *   6. 关闭indexwirter对象
        indexWriter.close();
    }

 

 

 

七.lucene查询索引:

1. 创建用户查询接口,提供一个输入关键字的地方

2. 创建查询

3. 执行查询

4. 渲染结果

 

 

具体代码示例:

/***
     * //
查询索引分析
     // 1.创建一个Directory对象,也就是索引库存放的位置
     // 2. 创建一个indexReader对象,需要制定Directory对象
     // 3. 创建一个indexSearcher对象,需要指定indexReader对象
     // 4. 创建一个TremQuery对象,制定查询的域和查询的关键字
     // 5. 执行查询
     // 6. 返回查询结果,遍历查询结果并输出
     // 7. 关闭indexReader对象
     */
   
public static void selectIndex(String keywords) throws IOException {
        //查询索引分析
        // 1.创建一个Directory对象,也就是索引库存放的位置
       
Directory directory=FSDirectory.open(new File("D:\\Documents\\Downloads\\day02_lucene\\索引存放位置"));
        // 2. 创建一个indexReader对象,需要指定Directory对象
       
IndexReader indexReader= DirectoryReader.open(directory);
        // 3. 创建一个indexSearcher对象,需要指定indexReader对象
       
IndexSearcher indexSearcher=new IndexSearcher(indexReader);
        // 4. 创建一个TremQuery对象,制定查询的域和查询的关键字
       
Query termQuery=new TermQuery(new Term("filename",keywords));
        // 5. 执行查询
       
TopDocs search = indexSearcher.search(termQuery, 10);
        // 6. 返回查询结果,遍历查询结果并输出
        //查询结果的总条数
       
System.out.println("查询结果的总条数"+search.totalHits);
        //遍历查询结果
       
for (ScoreDoc scoreDoc : search.scoreDocs) {
            //scoreDoc.doc就是document的id
           
Document document=indexSearcher.doc(scoreDoc.doc);

            //通过document对象展示出所有结果信息
           
System.out.println("filename="+document.get("filename"));
            System.out.println("filepath="+document.get("filepath"));
            System.out.println("filesize="+document.get("filesize"));
//            System.out.println("filecontent="+document.get("filecontent"));
            //
来一个分割符
           
System.out.println("=================================================");
        }

        // 7. 关闭indexReader对象
       
indexReader.close();
    }

 

 

 

 

八.分词器

如果检索的是英文,分词器使用标准的就可以,但是外国人编写的中文分词器总是不成功,

 

这里使用IK-analyzer

StandardAnalyzer:一个字一个字的

  CJKAnalyzer:两个字两个字  需要添加 lucene-analyzers-smartcn依赖

  SmartChineseAnalyzer:对中文的支持还算可以,但是英文有缺失字母的情况

第三方分词器:IK-analyzer

             依赖是:

               

<dependency>

                       <groupId>com.janeluo</groupId>

                       <artifactId>ikanalyzer</artifactId>

                       <version>2012_u6</version>

                       <exclusions>

                            <exclusion>

                                <groupId>org.apache.lucene</groupId>

                                <artifactId>lucene-queryparser</artifactId>

                            </exclusion>

                       </exclusions>

                   </dependency>

 

 

             需要三个配置文件

                        IKAnalyzer.cfg.xml 核心配置文件

                        ext.dic            扩展词典

                        stopword.dic       停用词典

 

 

九. 使用分词器进行查询

public static void selectIndex(String keywords) throws IOException, ParseException {
        //查询索引分析
        // 1.创建一个Directory对象,也就是索引库存放的位置
        Directory directory=FSDirectory.open(new File("D:\\Documents\\Downloads\\day02_lucene\\索引存放位置"));
        // 2. 创建一个indexReader对象,需要指定Directory对象
        IndexReader indexReader= DirectoryReader.open(directory);
        // 3. 创建一个indexSearcher对象,需要指定indexReader对象
        IndexSearcher indexSearcher=new IndexSearcher(indexReader);
        // 4. 创建一个TremQuery对象,制定查询的域和查询的关键字
        //创建一个分词器
        Analyzer analyzer=new IKAnalyzer();
          //几种查询
        //精确查询
//        Query termQuery=new TermQuery(new Term("filename",keywords));
  
//        //通配符查询,只要包含关键字都可以
//        Query termQuery=new WildcardQuery(new Term("filename","*"+keywords+"*"));
  
//        //模糊查询,容错性高
//        Query termQuery=new FuzzyQuery(new Term("filename",keywords));
  
  
     /*   //通配符查询,只要包含关键字都可以
        Query termQuery1=new WildcardQuery(new Term("filename","*"+keywords+"*"));
        //模糊查询,容错性高
        Query termQuery2=new FuzzyQuery(new Term("filename",keywords));
        //BooleanQuery 查询,可以查询多个条件
        BooleanQuery termQuery=new BooleanQuery();
        termQuery.add(termQuery1, BooleanClause.Occur.MUST);//must表示必须满足
        termQuery.add(termQuery2, BooleanClause.Occur.SHOULD);//其他条件查询完,如果满足本条件,则添加
        //must_not 表示必须不满足才执行*/
  
  
        //分词查询
        //1. 一个域的查询,如上
  
        //2. 多个域的查询
        QueryParser queryParser=new MultiFieldQueryParser(new String[]{"filename","filecontent"},analyzer);
        Query termQuery=queryParser.parse(keywords);
  
  
  
        // 5. 执行查询
        TopDocs search = indexSearcher.search(termQuery, 10);
        // 6. 返回查询结果,遍历查询结果并输出
        //查询结果的总条数
        System.out.println("查询结果的总条数"+search.totalHits);
        //遍历查询结果
        for (ScoreDoc scoreDoc : search.scoreDocs) {
            //scoreDoc.doc就是document的id
            Document document=indexSearcher.doc(scoreDoc.doc);
  
            //通过document对象展示出所有结果信息
            System.out.println("filename="+document.get("filename"));
            System.out.println("filepath="+document.get("filepath"));
            System.out.println("filesize="+document.get("filesize"));
  //            System.out.println("filecontent="+document.get("filecontent"));
            //来一个分割符
            System.out.println("=================================================");
        }
  
        // 7. 关闭indexReader对象
        indexReader.close();
    }

 

 

 

 

十. 打分

关键字占的比重及权重

 

 

举例说明

关键字占的比例即权重

spring.txt           分词后的结果:spring  txt               50%

spring_README.txt    分词后的结果:spring  README  txt       33%

spring的简介.txt     分词后的结果:spring  简介  简  介 txt  20%

 

spring是个非常流行的框架.txt

spring是个开发中非常流行的框架.txt

 

 

问题

为什么百度搜索时权重较低的广告可以排在最前面?

 

设置权重

 

可以设置boost值 默认是1.0

 

在添加索引的时候设置权重

Field fileContentField=new TextField("filecontent",fileContent,Field.Store.YES);
  //权重默认是1.0,越大权重越高
  fileContentField.setBoost(1.5f);
Field filePathField=new StringField("filepath",filePath,Field.Store.YES);
Field fileNameField=new TextField("fileName",fileName,Field.Store.YES);
Field filesizeField=new LongField("filesize",fileSize,Field.Store.YES);

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!