zoukankan      html  css  js  c++  java
  • lucene全文检索

    什么是全文检索

    将数据分为两类,

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

    结构化数据:

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

    查询的方式: 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);
  • 相关阅读:
    产品设计理应遵循哪些原则?
    产品经理必读的九步法
    exec
    Class convert
    Connecting method
    ASP.NET读写操作
    Encrypt Decrypt
    EventHandler, EventArgs
    Convert using code
    Dictionary List
  • 原文地址:https://www.cnblogs.com/aihuadung/p/11592894.html
Copyright © 2011-2022 走看看