A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 王高飞 于 2018-12-5 13:37 编辑

Lucene&solr:维护数据,实现全文检索的
                        Lucene:solr底层
                        solr:服务器
一 什么是全文检索
  数据分类:
                        结构化数据:有固定格式(数据类型)和有限的长度 比如:数据库表中的数据 元数据:关于数据的数据
                                                查询: 使用SQL语句查询结构化数据  速度快
                                                数据量大时 在数据库给某字段创建索引 但是索引不支持like(模糊)查询
                                                只能做等值查询
                                                解决模糊查询的问题 需要创建另外一套索引库:使用分词器
                                                
                        非结构化数据:没有固定格式(数据类型)也没有有限的长度 比如:word ppt excel pdf txt等磁盘上的文件
                                                查询: 1 目测 顺序扫描 挨个硬找 比较慢
                                                          2 IO读取
                                                          3 全文检索:
                                                                        
        全文检索:
                        对源数据创建索引+在索引上查询   电商项目
                索引:
                        将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,
                        然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。
                        这部分从非结构化数据中提取出的然后重新组织的信息,我们称之索引。
                        
                        

二 全文检索的应用场景
    1 搜索引擎: 谷歌 百度 搜狗 360
        2 站内搜索: 淘宝 京东 微博 论坛
          全文检索的数据不是直接来自数据库 而是来自通过数据库数据创建的索引库


三 怎么实现全文检索
        使用Lucene实现
        
四 Lucene的简介
        Lucene是apache下的一个开放源代码的全文检索引擎工具包。提供了完整的查询引擎和索引引擎,部分文本分析引擎。
        Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。
        目前我们使用核心core和分词器两个jar

五 Lucene实现全文检索的流程
        1 创建索引
           0 确定源文档:
                        要创建索引 使用全文检索的文件
           1 获取源文档:
             源文档是什么?
                        场景1:搜索引擎:指的是互联网上的所有网页
                        场景2:站内搜索:
                                        1 磁盘上的文件
                                        2 数据库表中的数据
                 获取源文档方式:
                          1 搜索引擎
                                        使用网络爬虫(网络机器人)得到的 爬虫访问互联网上的每一个网页,将获取到的网页内容存储起来。
                          2 站内搜索:
                                        1 磁盘上的文件:IO流
                                        2 数据库表中的数据:sql查询
           2 构建文档对象document
             每个document中的属性可以不同 每个document都需要有唯一的id
                 一个Document对象放的内容是:
                                一个网页的内容(网络地址URL 网页标题 网页内容)
                                一个文件中内容(文件名 地址 大小 内容等)  
                                表中的一条数据(一条数据每个列的内容 有多少列就应该创建多少个域)
           3 分析文档,对内容分词
                 使用原始的分词
                 文件spring.txt内容:The Spring Framework provides a comprehensive programming and configuration model.
                 分词:为了创建索引库
                                                        1 按空格分词:按空格把语句划分成单词
                                                        2 处理大小写:忽略单词的大小写
                                                        3 处理停用词:去除停用词
                                                        4 标点符号:去除标点符号
                 分词后:
                        name:spring
                        content:spring
                        content:framework
                        content:provides
                        content:comprehensive
                        content:programming
                        content:configuration
                        content:model
                                                
           4 创建索引(存储索引到索引库)
                        
                        1 一个文档document可以有多个域 不同的文档可以有不同的域 同一个Document可以有相同的Field(域名和域值都相同)
                        2 域Field:域名+域值
                          域名    Filename
                                          Content
                                          size
                                          path
                          域值 spring mvc l love you
                        3 term:不同的域中拆分出来的相同的单词是不同的term
                                    域名+单词内容 Filename:spring
                                                                  Content:love
                                                                  Content:provides
                                                                  Content:spring
                        4 对所有文档分析得出的语汇单元term进行索引
                          索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元从而找到Document(文档)。
                          
                        5 创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构。
                              倒排索引使得每个关键字索引对应多个文档ID,通过索引找到文档。
                        
                          传统方法是正排索引,根据文档去搜索关键词,根据文件找到该文件的内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大、搜索慢。
        2 查询索引:
                查询索引也是搜索的过程。搜索就是用户输入关键字,从索引(index)中进行搜索的过程。
                根据关键字搜索索引,根据索引找到对应的文档,从而找到要搜索的内容
        
                1 用户查询接口 输入查询关键字的位置
                2 创建查询
                3 执行查询
                4 渲染结果

六 Lucene入门案例
    1 导入jar :lucene-core-4.10.3.jar、lucene-analyzers-common-4.10.3.jar  commons-io.jar(读写本地文件)
        2 创建索引:
                第一步:创建一个java工程,并导入jar包。
                第二步:创建一个indexwriter对象。
                                1 指定索引库的存放位置Directory对象
                                2 指定一个分析器Analyzer,对文档内容进行分析。
                第二步:创建document对象。
                第三步:创建field对象,设置域名 域值 是否分析 将field添加到document对象中。
                第四步:使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
                第五步:关闭IndexWriter对象。
                源码:
                        //指定索引存放位置
                        Directory directory=FSDirectory.open(new File("D:\Everday\Lucene&solr\Lucene&solr-day01\资料\index"));
                        //创建一个标准分析库 分词器
                        Analyzer analyzer=new StandardAnalyzer();
                        //        //创建indexwriterCofig对象
                        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LATEST, analyzer);
                        ////创建indexwriter对象
                        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
                        //原文档
                        File dir = new File("D:\Everday\Lucene&solr\Lucene&solr-day01\资料\上课用的查询资料searchsource");
                        //获得文件夹内的所有文件
                        File[] listFiles = dir.listFiles();
                        for (File f : listFiles) {
                                //文件名
                                String fileName = f.getName();
                                //文件内容
                                String fileContent = FileUtils.readFileToString(f);
                                //文件路径
                                String filePath = f.getPath();
                                //文件的大小
                                long fileSize  = FileUtils.sizeOf(f);
                                //创建文件名域
                                //第一个参数:域的名称
                                //第二个参数:域的内容
                                //第三个参数:是否分析 索引 存储
                                Field fileNameField = new TextField("filename", fileName, Store.YES);
                                //文件内容域
                                Field fileContentField = new TextField("content", fileContent, Store.YES);
                                //文件路径域
                                Field filePathField = new StoredField("path", filePath);
                                //文件大小域
                                Field fileSizeField = new LongField("size", fileSize, Store.YES);
                                
                                //创建document对象
                                Document document = new Document();
                                document.add(fileNameField);
                                document.add(fileContentField);
                                document.add(filePathField);
                                document.add(fileSizeField);
                                //创建索引,并写入索引库
                                indexWriter.addDocument(document);
                        }
                        
                        //释放资源
                        indexWriter.close();
                }
               
                使用luke工具查看索引文件,运行bat文件 打开软件
               
        2 查询索引
                第一步:创建一个Directory对象,指定索引库存放的位置。
                第二步:创建一个indexReader对象,需要指定Directory对象。
                第三步:创建一个indexsearcher对象,需要指定IndexReader对象
                第四步:创建一个TermQuery对象,指定查询的域和查询的关键词。
                第五步:执行查询方法。
                                query:指定条件
                            n:查询数据量的限制
                第六步:返回查询结果TopDocs。遍历查询结果并输出。
                                TopDocs:提供了获得结果的属性
                                  topDocs.totalHits:匹配搜索条件的总记录数
                                  topDocs.scoreDocs:顶部匹配记录
                第七步:关闭IndexReader对象
                源码:
                            //指定索引库存放的路径
                                Directory directory = FSDirectory.open(new File("D:\Everday\Lucene&solr\Lucene&solr-day01\资料\index"));
                                //创建indexReader对象
                                IndexReader indexReader = DirectoryReader.open(directory);
                                //创建indexsearcher对象
                                IndexSearcher indexSearcher = new IndexSearcher(indexReader);
                                //创建查询
                                Query query = new TermQuery(new Term("filename", "spring"));
                                //执行查询
                                //第一个参数是查询对象,第二个参数是查询结果返回的最大值
                                TopDocs topDocs = indexSearcher.search(query, 100);
                                //查询结果的总条数
                                System.out.println("查询结果的总条数:"+ topDocs.totalHits);
                                //遍历查询结果
                                //topDocs.scoreDocs存储了document对象的id
                                for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
                                        //scoreDoc.doc属性就是document对象的id
                                        //根据document的id找到document对象
                                        Document document = indexSearcher.doc(scoreDoc.doc);
                                        System.out.println(document.get("filename"));
                                        System.out.println(document.get("content"));
                                        System.out.println(document.get("path"));
                                        System.out.println(document.get("size"));
                                        System.out.println("------------------------------------");
                                }
                                //关闭indexreader对象
                                indexReader.close();
                        }               
                        
八 分词器 分词器
        apache自带的:中文分析效果不好
                1 StandardAnalyzer:
                        单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”,
                        效果:“我”、“爱”、“中”、“国”。
                2 CJKAnalyzer
                        按两个字进行切分。如:“我是中国人”,效果:“我是”、“是中”、“中国”“国人”。
                3 SmartChineseAnalyzer
                        导包 lucene-analyzers-smartcn-4.10.3.jar
                        对中文支持较好,但扩展性差,扩展词库,禁用词库和同义词库等不好处理
        第三方提供的: 支持中文分析效果好
                IKAnalyzer :
                导入jar:IKAnalyzer2012FF_u1.jar
                配置两个配置文件:stopword.dic和ext.dic 对中文分词效果较好 也可以自己指定禁用词和扩展词
九 分词器Analyzer的使用时机
                1 创建索引时使用Analyzer
                        对于一些域值不需要分析器
                        1 不作为查询条件的内容,比如文件路径
                        2 不是匹配内容中的词而匹配Field的整体内容,比如订单号、身份证号等。
                2 查询时也需要分词
        注意:搜索使用的分析器要和索引使用的分析器一致。        
        
               
               

16 个回复

倒序浏览
学习了,感谢大神详细的总结
回复 使用道具 举报
liuchengwei1 来自手机 中级黑马 2018-12-5 12:18:48
藤椅
回复 使用道具 举报
Vicky韦 来自手机 黑马粉丝团 2018-12-5 12:35:19
板凳
回复 使用道具 举报
厉害厉害厉害
回复 使用道具 举报
啦啦啦
回复 使用道具 举报
66666
回复 使用道具 举报
HFFFX 来自手机 中级黑马 2018-12-5 14:50:11
8#
赞赞赞
回复 使用道具 举报
回复 使用道具 举报
回复 使用道具 举报
回复 使用道具 举报
很详细!
回复 使用道具 举报
很详细!
回复 使用道具 举报
回复 使用道具 举报
优秀
回复 使用道具 举报
大神
回复 使用道具 举报
很金典  666不错不错
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马