娱乐头条-04lucene

1.搜索引擎

2.lucene

 

一、搜索引擎

1.什么是搜索引擎

        搜索引擎是指根据一定的策略、运用特定的计算机程序从互联网上搜集信息,在对信息进行组织和处理后,为用户提供检索服务,将用户检索相关的信息展示给用户的系统。例如: 百度 谷歌

2.搜索引擎基本的运行原理

3.原始数据库查询的缺陷

  • 慢, 当数据库中的数据量很庞大的时候, 整个的查询效率非常低, 无法及时返回内容
  • 搜索效果比较差, 只能根据用户输入的完整关键字的进行首尾的模糊匹配
  • 如果用户输入的关键字出现错别字, 或者多输入了内容, 可能就导致结果远离用户期望的内容

4.倒排索引技术

        倒排索引, 又称为反向索引: 以字或者词,甚至是一句话一段话作为一个关键字进行索引, 每一个关键字都会对应着一个记录项, 记录项中记录了这个关键字出现在哪些文档中,以及在此文档的什么位置上

       

为什么说倒排索引可以提升查询的效率和精准度呢?

      ​ 倒排索引, 是将数据提前按照格式分词放好,建立索引, 当用户进行搜索, 将用户的关键字进行分词, 然后根据分词后的单词到索引库中寻找对应词条,根据词条, 查到对应所在的文档位置, 将其文档内容直接获取即可

二、lucene

       lucene是Apache提供的一个开源的全文检索引擎工具包, 其本质就是一个工具包, 而非一个完整的搜索引擎, 但是我们可以通过Lucene来构建一个搜索引擎

 lucene建立索引库的原理

 lucene查询的原理

1.lucene 与solr的关系

  • Lucene: 底层的api, 工具包
  • solr: 基于Lucene开发的企业级的搜索引擎产品

2.使用lucene如何构建索引

1、添加依赖

        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>4.10.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queries</artifactId>
            <version>4.10.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-test-framework</artifactId>
            <version>4.10.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>4.10.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>4.10.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-highlighter</artifactId>
            <version>4.10.2</version>
        </dependency>

添加编译插件(自带的版本较低,会报错)

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>

2、书写写入索引的代码

    @Test
    public void testWriterIndex() throws Exception{
        //写入索引

        //创建目录对象
        Directory directory = new SimpleFSDirectory(new File("D:\\index"));
        //创建索引写入器配置对象
        IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_2,new SimpleAnalyzer());
        //设置Lucene的打开索引库的方式
        config.setOpenMode(IndexWriterConfig.OpenMode.CREATE);

        //创建索引写入器对象
        IndexWriter indexWriter = new IndexWriter(directory,config);

        //创建字段类型
        FieldType fieldType = new FieldType();
        fieldType.setStored(true);//是否存储到索引库
        fieldType.setTokenized(true);//是否分词
        fieldType.setIndexed(true);//是否创建索引


        //创建文档对象
        Document document = new Document();
        document.add(new Field("title","lucene简介",fieldType));
        document.add(new Field("content","Lucene是Apache提供的一个开源的全文检索引擎工具包, 其本质就是一个工具包",fieldType));

        //添加内容
        indexWriter.addDocument(document);

        //写入索引
        indexWriter.commit();

        //关闭资源
        indexWriter.close();

    }
}

3.索引查看工具

链接https://pan.baidu.com/s/1jXCbufIE2AwYGbusZ_ugWA 
提取码:i82i

执行run.bat

4.API详解

  • IndexWriter: 索引写入器对象

其主要的作用, 添加索引, 修改索引和删除索引

  • 创建此对象的时候, 需要传入Directory和indexWriterConfig对象
  • Directory: 目录类, 用来指定索引库的目录
  • 常用的实现类:
    • FSDirectory: 用来指定文件系统的目录, 将索引信息保存到磁盘上
    • 优点: 索引可以进行长期保存, 安全系数高
    • 缺点: 读取略慢
    • RAMDriectory: 内存目录, 将索引库信息存放到内存中
    • 优点: 读取速度快
    • 缺点: 不安全, 无法长期保存, 关机后就消失了
  • IndexWriterConfig: 索引写入器的配置类
  • 创建此对象, 需要传递Lucene的版本和分词器
  • 作用:
    • 作用1 : 指定Lucene的版本和需要使用的分词器
    • 作用2: 设置Lucene的打开索引库的方式: setOpenMode();

        //参数值: APPEND CREATE   CREATE_OR_APPEND
        /**
         * APPEND: 表示追加, 如果索引库存在, 就会向索引库中追加数据, 如果索引库不存在, 直接报错
         *
         * CREATE: 表示创建, 不管索引库有没有, 每一次都是重新创建一个新的索引库
         *
         * CREATE_OR_APPEND: 如果索引库有, 就会追加, 如果没有 就会创建索引库
                默认值也是 CREATE_OR_APPEND
         */
        config.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);

  • Document: 文档

​       在Lucene中, 每一条数据以文档的形式进行存储, 文档中也有其对应的属性和值, Lucene中一个文档类似数据库的一个表, 表中的字段类似于文档中的字段,只不过这个文档只能保存一条数据

       ​ Document看做是一个文件, 文件的属性就是文档的属性, 文件对应属性的值就是文档的属性的值 content

  • 一个文档中可以有多个字段, 每一个字段就是一个field对象,不同的文档可以有不同的属性
  • 字段也有其对应数据类型, 故Field类也提供了各种数据类型的实现类

Field类

数据类型

Analyzed是否分析

Indexed是否索引

Stored是否存储

说明

StringField(FieldName, FieldValue,Store.YES))

字符串

N

Y

Y或N

这个Field用来构建一个字符串Field,但是不会进行分析,会将整个串存储在索引中,比如(订单号,姓名等)是否存储在文档中用Store.YES或Store.NO决定

LongField(FieldName, FieldValue,Store.YES)

Long型

Y

Y

Y或N

这个Field用来构建一个Long数字型Field,进行分析和索引,比如(价格)是否存储在文档中用Store.YES或Store.NO决定

StoredField(FieldName, FieldValue)

重载方法,支持多种类型

N

N

Y

这个Field用来构建不同类型Field不分析,不索引,但要Field存储在文档中

TextField(FieldName, FieldValue, Store.NO)或TextField(FieldName, reader)

字符串或流

Y

Y

Y或N

如果是一个Reader, lucene猜测内容比较多,会采用Unstored的策略.

名称解释:

​    分析: 是否将字段的值进行分词

​    索引: 指的是能否被搜索

   ​ 是否保存: 指的的初始值是否需要保存

如果一个字段中的值可以被分词, 那么必然是支持搜索的

  • Analyzer: 分词器:

​        用于对文档中的数据进行分词, 其分词的效果取决于分词器的选择, Lucene中根据各个国家制定了各种语言的分词器,对中文有一个ChineseAnalyzer 但是其分词的效果, 是将中文进行一个一个字的分开

       针对中文分词一般只能使用第三方的分词词:

       

       一般采用IK分词器

5.集成IK分词器

1、导入相关依赖

        <dependency>
            <groupId>com.janeluo</groupId>
            <artifactId>ikanalyzer</artifactId>
            <version>2012_u6</version>
        </dependency>

2、将上面的简单分词器换成ik分词器

        //创建索引写入器配置对象
        IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_2,new IKAnalyzer());

如果出现新的词,例如:

        document.add(new Field("title","网络词",fieldType));
        document.add(new Field("content","吊炸天不明觉厉",fieldType));

  • 高级使用:

            ik分词器在2012年更新后, 就在没有更新, 其原因就取决于其强大的扩展功能,以保证ik能够持续使用

链接https://pan.baidu.com/s/1SXy2dcYTz-vp4MAQ0D6nmw 
提取码:ir4f

  • ik支持对自定义词库, 其可以定义两个扩展的词典
    • 扩展词典(新创建词功能):有些词IK分词器不识别 例如:“传智播客”,“碉堡了”
    • 停用词典(停用某些词功能)有些词不需要建立索引  例如:“哦”,“啊”,“的”
  • 如何使用:

       

       将此三个文件复制到项目中

       

       

       接着在ext.dic中设置需要进行分词的内容即可, 在stopword中设置不被分词的内容即可

       

       

       

6.查询索引

public class Search {

    @Test
    public void testIndexSearch() throws Exception{

        //创建索引读取id
        IndexReader reader = DirectoryReader.open(new SimpleFSDirectory(new File("d:\\index")));

        //创建索引的搜索对象
        IndexSearcher searcher = new IndexSearcher(reader);

        //执行搜索
        /*
        * 第一个参数:
        * 第二个参数:返回多少条数据
        * */
        QueryParser parser = new QueryParser("content",new IKAnalyzer());
        Query query = parser.parse("不明觉厉");
        TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);

        //System.out.println(topDocs.totalHits);//命中的文档数
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for(ScoreDoc scoreDoc:scoreDocs){
            System.out.println("得分为:"+scoreDoc.score);
            System.out.println("文档id为:"+scoreDoc.doc);

            Document document = searcher.doc(scoreDoc.doc);
            List<IndexableField> fields = document.getFields();
            for(IndexableField field:fields){
                System.out.println(document.getField(field.name()).stringValue());
            }
        }

    }
}

7.查询相关API详解

  • IndexSearcher: Lucene中索引查询对象, 用来执行查询和排序操作
  • 常用方法:
    • search(Query query, int n);//执行查询
    • 参数1: 查询条件
    • 参数2: 返回的最大条数
    • search(Query query, int n,Sort sort);
    • 参数1: 查询的条件
    • 参数2: 返回的最大的条数
    • 参数3: 排序
    • doc(int id);//根据文档id查询文档对象
  • IndexReader: 索引库读取工具
  • 使用DirectoryReader来打开索引库
  • Query:查询对象
  • 获取方式:
    • 通过查询解析器
    • 单字段的解析器: queryParse
    • 多字段的解析器: multiFieldQueryParse
    • 使用Lucene自定义的实现类
    • Lucene中提供了五种常用的多样化的查询
  • TopDocs:查询结果对象
  • 第一部分: 查询到的总条数
    • int topDocs.totalHits
  • 第二部分: 得分文档的数组
    • ScoreDoc[] topDocs.scoreDocs;
  • ScoreDoc: 得分文档对象
  • 第一部分: 文档的id
    • topDoc.doc
  • 第二部分: 文档的得分
    • topDoc.score

8.多样化查询

准备数据:(1)向索引库中多添加几条索引

                  (2)提取一个查询的方法, 传递不同的query, 即可

    public void mulipartQuery(Query query) throws Exception{

        IndexReader reader = DirectoryReader.open(new SimpleFSDirectory(new File("D:\\index")));
        IndexSearcher searcher = new IndexSearcher(reader);


        TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);


        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {

            System.out.println("得分为:"+scoreDoc.score);
            System.out.println("文档Id为:"+scoreDoc.doc);

            Document document = searcher.doc(scoreDoc.doc);

            System.out.println("文档的title为:"+document.getField("title").stringValue());
            System.out.println("文档的content为:"+document.getField("content").stringValue());
        }
    }

1、词条查询

    //1.词条查询
    @Test
    public void testTermQuery() throws Exception{
        TermQuery query = new TermQuery(new Term("title","简介"));
        mulipartQuery(query);
    }

词条查询是一个不可在分割内容, 可以把词条看做是一个分词后的单词

词条查询在书写词条内容的时候, 是不允许输入错误的

2、模糊查询

    //2.模糊查询
    @Test
    public void testFuzzyQuery() throws Exception{
        FuzzyQuery query = new FuzzyQuery(new Term("title","lucene"));
        mulipartQuery(query);
    }

 最大编辑次数: 2(0~2)
     2 : 替换, 修改, 补位 : 这三种操作只要能够在2次(每一此都是单个字符和单个字符的处理)的范围内将词条恢复回来, 就可以查询到数据
    过半机制: 如果词条是小于等于4的, 最大编辑次数就为1了, 如果只有二个, 压根就没有最大编辑次数

3、通配符查询

    //3.通配符查询
    @Test
    public void testWildCardQuery() throws Exception{
        WildcardQuery query = new WildcardQuery(new Term("title","lucene"));
        mulipartQuery(query);
    }

* : 占用 0 ~ 多个字符
 ? : 占用一个字符

4、数值范围查询

准备数据,在Writer类中写入索引:数字

        //创建文档对象
        Document document1 = new Document();
        document1.add(new IntField("title",10, Field.Store.YES));
        document1.add(new Field("content","10",fieldType));
        //创建文档对象
        Document document2 = new Document();
        document2.add(new IntField("title",20, Field.Store.YES));
        document2.add(new Field("content","20",fieldType));
        //创建文档对象
        Document document3 = new Document();
        document3.add(new IntField("title",30, Field.Store.YES));
        document3.add(new Field("content","30",fieldType));

        //添加内容
        indexWriter.addDocument(document1);
        indexWriter.addDocument(document2);
        indexWriter.addDocument(document3);
    //4.数值范围查询
    @Test
    public void testRangeQuery() throws Exception{
        //参数1: 默认查询的字段
        //参数2: 最小值
        //参数3: 最大值
        //参数4: 是否包含最小值
        //参数五: 是否包含最大值
        NumericRangeQuery<Integer> query = NumericRangeQuery.newIntRange(
                "title",10,30,true,true
        );
        mulipartQuery(query);
    }

5、组合查询

    //5.组合查询
    @Test
    public void testBooleanQuery() throws Exception{
        BooleanQuery query = new BooleanQuery();
        NumericRangeQuery<Integer> rangeQuery = NumericRangeQuery.newIntRange(
                "title",10,20,true,true
        );
        query.add(new TermQuery(new Term("content","solr")), BooleanClause.Occur.MUST_NOT);
        query.add(rangeQuery, BooleanClause.Occur.SHOULD);
        mulipartQuery(query);
    }

组合查询:本身自己是没有任何的条件的, 组合查询的目的是为了将其他的查询条件, 并入组合查询的条件中, 实现多条件查询
     MUST : 必须的. 这个条件是必须存在的, 获取到的结果, 必须是包含这个条件的内容
     MUST_NOT: 不必须. 这个条件是必须不包含的, 获取到的结果, 是不能有这个条件里的内容
     SHOULD:  可选的, 如果这个条件能获取到数据, 那么就展示, 如果没有获取到数据, 就不展示, 同时也不会影响其他的条件

9.lucene的索引修改

    @Test
    public void updateIndex() throws Exception{

        Directory directory = new SimpleFSDirectory(new File("D:\\index"));
        IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_2,new IKAnalyzer());

        IndexWriter writer = new IndexWriter(directory, config);

        FieldType fieldType = new FieldType();
        fieldType.setStored(true);//是否存储到索引库
        fieldType.setTokenized(true);//是否分词
        fieldType.setIndexed(true);//是否创建索引

        Document document = new Document();
        document.add(new Field("title","lucene简介",fieldType));
        document.add(new Field("content","lucene是一个全文检索的工具包,是solr的底层原理",fieldType));
        writer.updateDocument(new Term("title","lucene"),document);

        writer.commit();
        writer.close();

    }

10.lucene的删除

    @Test
    public void delIndex() throws Exception{

        Directory directory = new SimpleFSDirectory(new File("D:\\index"));
        IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_2,new IKAnalyzer());

        IndexWriter writer = new IndexWriter(directory, config);

        //writer.deleteDocuments(new Term("title","lucene"));
        writer.deleteAll();

        writer.commit();
        writer.close();

    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值