zoukankan      html  css  js  c++  java
  • lucene:初始(概念、创建索引、执行查询、分析器)

    1、基本概念

    (1)数据分类

    结构化数据:具有固定格式或有限长度的数据,如:数据库、元数据等

    非结构化数据:不定长或无固定格式的数据,如:邮件、word文档等

    (2)非结构化数据的查询方法

    顺序扫描法:

    所谓顺序扫描,比如要找内容包含某一个字符串的文件,就是一个文档一个文档的看,对于每一个文档,从头看到尾,如果此文档包含此字符串,则此文档为我们要找的文件,换着找下一个文件,直到扫描完所有的文件,如利用windows的搜索也可以搜索文件内容,但是速度太慢

    全文检索:

    先建立索引然后再对索引进行搜索的过程

    索引的创建需要耗费资源,但是一旦创建了索引就可以使用多次

    lucene可以实现全文检索,它提供了完整的查询引擎和索引引擎,部分文本分析引擎

    数据量大、数据结构不固定的数据可以采用全文检索,如:百度、电商网站等搜索引擎

    (3)solr与lucene

     solr是基于lucene的

    使用率高

    (4)下载lucene

    下载压缩包解压即可

    2、索引与搜索流程

    获取文档:将文档从磁盘读取到内存中

    索引库包含原始文档和索引

    原始文档:互联网的页面、数据库中的数据、磁盘上的文件等

    lucene不提供信息采集的类库,需要通过爬虫程序来实现信息的采集

    每一个文档对象都有一个唯一的ID,文档对象的属性再这里被称为域,例如:创建时间就是文档对象的一个域,而ID不是域

    3、分析文档(英文文档)

    将原始内容创建为包含域(Field)的文档(document),需要再对域中的内容进行分析,分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号等过程生成最终的语汇单元,可以将语汇单元理解为一个一个的单词。每一个单词叫做一个term,不同的域中拆分出来的单词是不同的term。

    4、lucene的使用

    (1)导包

    核心包:

     lucene-analyzers-common:

    lucene-queryparser:

     

     其他:

     (2)创建索引

     @Test
        public void testIndex() throws Exception {
            //指定一个分析器,对文档内容进行分析。
            Analyzer analyzer = new StandardAnalyzer();
            IndexWriterConfig config = new IndexWriterConfig(analyzer);
            //指定索引库的存放位置Directory对象,保存索引到内存中 (内存索引库)
            Directory directory = FSDirectory.open(new File("E:\test1").toPath());
            //创建一个indexwriter对象
            IndexWriter indexWriter = new IndexWriter(directory, config);
            //创建field对象,将field添加到document对象中。
            File f = new File("E:\test");
            File[] listFiles = f.listFiles();
            for (File file : listFiles) {
                //创建document对象
                Document document = new Document();
                // 文件名称
                String file_name = file.getName();
                //是否分析、是否索引、是否存储在索引中
                Field fileNameField = new TextField("fileName", file_name, Field.Store.YES);
                // 文件大小
                long fileSize = FileUtils.sizeOf(file);
                Field fieldSizeValue = new LongPoint("size",fileSize);
                Field fieldSizeStore = new StoredField("size",fileSize);
                // 文件路径
                String file_path = file.getPath();
                Field filePathField = new StoredField("filePath", file_path);
                // 文件内容
                String file_content = FileUtils.readFileToString(file);
                Field fileContentField = new TextField("fileContent", file_content, Field.Store.NO);
                document.add(fileNameField);
                document.add(filePathField);
                document.add(fileContentField);
                document.add(fieldSizeValue);
                document.add(fieldSizeStore);
                //使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
                indexWriter.addDocument(document);
            }
            //关闭IndexWriter对象。
            indexWriter.close();
        }

    运行结果:

     (3)执行查询(搜索索引)

     @Test
        public void testSearch() throws Exception {
            //创建一个Directory对象,也就是索引库存放的位置
            Directory directory = FSDirectory.open(new File("E:\test1").toPath());// 磁盘
            //创建一个indexReader对象,需要指定Directory对象
            IndexReader indexReader = DirectoryReader.open(directory);
            //创建一个indexsearcher对象,需要指定IndexReader对象
            IndexSearcher indexSearcher = new IndexSearcher(indexReader);
            //创建一个TermQuery对象,指定查询的域和查询的关键词
            Query query = new TermQuery(new Term("fileName", "1"));
            //执行查询
            TopDocs topDocs = indexSearcher.search(query, 10);
            //返回查询结果,遍历查询结果并输出
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;
            for (ScoreDoc scoreDoc : scoreDocs) {
                int doc = scoreDoc.doc;
                Document document = indexSearcher.doc(doc);
                // 文件名称
                String fileName = document.get("fileName");
                System.out.println(fileName);
                // 文件内容
                String fileContent = document.get("fileContent");
                System.out.println(fileContent);
                // 文件大小
                String fileSize = document.get("fileSize");
                System.out.println(fileSize);
                // 文件路径
                String filePath = document.get("filePath");
                System.out.println(filePath);
            }
            // 第七步:关闭IndexReader对象
            indexReader.close();
        }

    执行结果:

    1.txt
    null
    null
    E:	est1.txt

    因为在创建文件索引的时候没有添加文件的内容和文件的大小的域,因此,这里的查询为空

    5、分析器

    搜索使用的分析器和索引使用的分析器要一致

    (1)英文分析器

    分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号等过程生成最终的语汇单元,可以将语汇单元理解为一个一个的单词。每一个单词叫做一个term,不同的域中拆分出来的单词是不同的term。

     @Test
        public void testTokenStream() throws Exception {
            // 创建一个标准分析器对象
            Analyzer analyzer = new StandardAnalyzer();
            // 获得tokenStream对象,第一个参数:域名,可以随便给一个,第二个参数:要分析的文本内容
            TokenStream tokenStream = analyzer.tokenStream("test",
                    "Binzhou Medical University is a common medical university at provincial level in Shandong" +
                            " Province,and its predecessor was the Public Medical School of Shandong University " +
                            "originally established in 1946.");
            // 添加一个引用,可以获得每个关键词
            CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
            // 添加一个偏移量的引用,记录了关键词的开始位置以及结束位置
            OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
            // 将指针调整到列表的头部
            tokenStream.reset();
            // 遍历关键词列表,通过incrementToken方法判断列表是否结束
            while (tokenStream.incrementToken()) {
                // 关键词的起始位置
                System.out.println("start->" + offsetAttribute.startOffset());
                // 取关键词
                System.out.println(charTermAttribute);
                // 结束位置
                System.out.println("end->" + offsetAttribute.endOffset());
            }
            tokenStream.close();
        }

    分词效果:

    start->0
    binzhou
    end->7
    start->8
    medical
    end->15
    start->16
    university
    end->26
    start->32
    common
    end->38
    start->39
    medical
    end->46
    start->47
    university
    end->57
    start->61
    provincial
    end->71
    start->72
    level
    end->77
    start->81
    shandong
    end->89
    start->90
    province
    end->98
    start->103
    its
    end->106
    start->107
    predecessor
    end->118
    start->127
    public
    end->133
    start->134
    medical
    end->141
    start->142
    school
    end->148
    start->152
    shandong
    end->160
    start->161
    university
    end->171
    start->172
    originally
    end->182
    start->183
    established
    end->194
    start->198
    1946
    end->202

    (2)中文分析器

    导包:

     @Test
        public void testTokenStream() throws Exception {
            // 创建一个标准分析器对象
            Analyzer analyzer = new SmartChineseAnalyzer();
            // 获得tokenStream对象,第一个参数:域名,可以随便给一个,第二个参数:要分析的文本内容
            TokenStream tokenStream = analyzer.tokenStream("test",
                    "我爱你中国,我爱你春天蓬勃的秧苗,我爱你秋日金黄的硕果");
            // 添加一个引用,可以获得每个关键词
            CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
            // 添加一个偏移量的引用,记录了关键词的开始位置以及结束位置
            OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
            // 将指针调整到列表的头部
            tokenStream.reset();
            // 遍历关键词列表,通过incrementToken方法判断列表是否结束
            while (tokenStream.incrementToken()) {
                // 关键词的起始位置
                System.out.println("start->" + offsetAttribute.startOffset());
                // 取关键词
                System.out.println(charTermAttribute);
                // 结束位置
                System.out.println("end->" + offsetAttribute.endOffset());
            }
            tokenStream.close();
        }

    分词效果:

    start->0
    我
    end->1
    start->1
    爱
    end->2
    start->2
    你
    end->3
    start->3
    中国
    end->5
    start->6
    我
    end->7
    start->7
    爱
    end->8
    start->8
    你
    end->9
    start->9
    春天
    end->11
    start->11
    蓬勃
    end->13
    start->13
    的
    end->14
    start->14
    秧苗
    end->16
    start->17
    我
    end->18
    start->18
    爱
    end->19
    start->19
    你
    end->20
    start->20
    秋日
    end->22
    start->22
    金黄
    end->24
    start->24
    的
    end->25
    start->25
    硕果
    end->27

    但是该分词器扩展性差:

    TokenStream tokenStream = analyzer.tokenStream("test",
                    "硬核,柠檬精、“我酸了”,奥利给");

    分词结果:

    start->0
    硬
    end->1
    start->1
    核
    end->2
    start->3
    柠檬精
    end->6
    start->8
    我
    end->9
    start->9
    酸
    end->10
    start->10
    了
    end->11
    start->13
    奥
    end->14
    start->14
    利
    end->15
    start->15
    给
    end->16

    IK分词器:

    导包、创建配置文件

     ext是自己导入的词语,stopword是忽略的词语

     配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">  
    <properties>  
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 -->
        <entry key="ext_dict">ext.dic;</entry> 
        
        <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords">stopword.dic;</entry> 
        
    </properties>

    测试代码:

      @Test
        public void testTokenStream() throws Exception {
            // 创建一个标准分析器对象
            Analyzer analyzer = new IKAnalyzer();
            // 获得tokenStream对象,第一个参数:域名,可以随便给一个,第二个参数:要分析的文本内容
            TokenStream tokenStream = analyzer.tokenStream("test", "硬核,柠檬精,我酸了,奥利给");
            // 添加一个引用,可以获得每个关键词
            CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
            // 添加一个偏移量的引用,记录了关键词的开始位置以及结束位置
            OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
            // 将指针调整到列表的头部
            tokenStream.reset();
            // 遍历关键词列表,通过incrementToken方法判断列表是否结束
            while (tokenStream.incrementToken()) {
                // 关键词的起始位置
                System.out.println("start->" + offsetAttribute.startOffset());
                // 取关键词
                System.out.println(charTermAttribute);
                // 结束位置
                System.out.println("end->" + offsetAttribute.endOffset());
            }
            tokenStream.close();
        }

    测试结果:

    加载扩展词典:ext.dic
    加载扩展停止词典:stopword.dic
    start->0
    硬核
    end->2
    start->3
    柠檬精
    end->6
    start->3
    柠檬
    end->5
    start->5
    精
    end->6
    start->11
    奥利给
    end->14
  • 相关阅读:
    从零开始学 Web 之 Vue.js(一)Vue.js概述,基本结构,指令,事件修饰符,样式
    从零开始学 Web 之 Vue.js(二)过滤器,按键修饰符,自定义指令
    js获取某个时间段前多长时间
    Object.create()详解
    React Redux
    react 路由按需加载
    react @types/react-router-dom报错
    create-react-app 创建react ts项目启动报错
    十进制转二进制、八进制、十六进制(js)
    代码编辑器设置自定义提示
  • 原文地址:https://www.cnblogs.com/zhai1997/p/13276105.html
Copyright © 2011-2022 走看看