• solr快速上手:managed-schema标签详解(三)


    0. 引言

    core核心是solr中的重中之重,类似数据库中的表,在搜索引擎中也叫做索引,在solr中索引的建立,要先创建基础的数据结构,即schema的相关配置,今天继续来学习solr的核心知识:

    solr快速上手:solr简介及安装(一)

    solr快速上手:核心概念及solr-admin界面介绍(二)

    1. schema标签

    schema实际上就是solr核心的数据结构,即字段的定义集。

    在solr安装目录下,有这样一个文件夹server/solr/configsets/_default/conf,里面附带了要创建索引的默认的基础配置文件。我们可以通过复制这个文件夹下的配置文件,来帮助我们快速创建索引

    这些文件中有两个核心的配置文件需要我们掌握:

    • menaged-schema: 字段配置文件
    • solrconfig.xml:solr核心配置文件
      在这里插入图片描述

    但在我们真正开始创建之前,还是要先学习其中schema的常用标签

    首先我们需要知道,我们字段结构的定义都是在managed-schema文件中的,当然有时我们能看到又使用的是schema.xml文件,这是因为solr提供了两种定义模式,默认使用managed-schema,如果需要使用schema.xml,则需要在solrconfig.xml中配置如下标签

    <schemaFactory class="ClassicIndexSchemaFactory"/>
    
    • 1

    通过上述文件夹中复制下来的managed-schema已经有各类标签的使用案例了,只不过都是注释的,我们来详细看看几个常用的标签:

    <schema name="example" version="1.5">
       
        <field name="id" type="int" indexed="true" stored="true" multiValued="false" required="true"/>
        ...
    
    	<dynamicField name="*_i"  type="pint"    indexed="true"  stored="true"/>
        ...
    
        <uniqueKey>iduniqueKey>
    	
    	<copyField source="sourceFieldName" dest="destinationFieldName"/>
    
        <fieldtype name="textSimple" class="solr.TextField">
            <analyzer>
                <tokenizer class="org.lionsoul.jcseg.solr.JcsegTokenizerFactory" mode="detect"/>
            analyzer>
        fieldtype>
        <fieldType name="string" class="solr.StrField" sortMissingLast="true"/>
        ...
    schema>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    1.1 field 字段标签

    filed标签用于配置字段信息,该标签中包含如下属性:

    • name: 字段名称,值要求唯一
    • type: 字段数据类型

    支持哪些常用的数据类型
    string 字符串
    int, long 整数
    float, double 浮点数
    date 日期时间
    bool 布尔类型
    text 文本类型
    binary 二进制类型

    • indexed: 当前字段是否创建索引,默认值为true

    这里的索引指的是什么?
    因为solr使用倒排索引,所以创建索引的含义,就是将字段值包含在倒排索引中,也就是用该值分词创建倒排索引,从而支持基于该字段的搜索和过滤。

    创建索引的好处和坏处?
    好处是提高了查询小了,坏处当然是增加了存储空间占用,而且当字段值本身很大时,创建索引也会带来一定的性能损耗。因此在指定索引字段时,也要综合考虑。

    • stored: 当前字段是否存储,默认为true

    是否存储,指的是存储到哪里?
    配置该字段的值是否存储到solr本身的存储库中,如果存储,那么当查询后的显示就不需要再查询数据源了,对于只需要排序、索引的字段,则可以设置为false来节约空间

    比如设置indexed=true, stored=false, 则表示该字段值用于创建索引,但不做存储吗?
    是的,该字段值不做存储,但是值会被分词用于创建倒排索引,如此当查询的结果需要再显示该字段时,就需要再次查询数据源来显示,而查询数据源本身是相对较慢的操作

    这里的数据源到底指的是什么?
    solr的数据源可能是数据库、文件、接口等,比如配置了solr数据是从mysql通过dataimport同步过来了,那么数据源就是mysql,查询数据源就表示通过sql再查一遍mysql,所以速度自然就慢

    stored=true的好处和坏处?
    好处是提高读取性能,直接存储在solr了,无需再从数据源获取,提高查询效率;坏处当然是占用磁盘空间,对于海量的数据时,如果不需要显示,仅仅只是做索引则不用存储,存储也意味着更高的磁盘、网络IO

    • docValues: 是否启用点列存储当前字段值,默认为false, 当需要字段做排序或者聚合查询时需要设置为true

    什么是点列存储?
    点列存储(也叫列存储)是倒排索引之外的一种存储结构,我们更加熟悉的是数据库的行存储,但实际上像oracle,sqlserver都已经在支持列存储,列存储是指的是按照列来进行分组存储
    比如我们有如下的几行数据

    nameagesexaddressschool
    张三28广州市xxx路南京大学
    李四18北京市xxx路湖南大学
    丽丽19福州市xxx路江南大学

    这几个数据按行存储的话,在磁盘中的存储方式如下所示
    同一行的数据是放在一起的
    在这里插入图片描述
    而列存储的话,就是同一列的数据放在一起
    在这里插入图片描述
    这样存储的好处在于当我们需要对年龄进行分组的时候,我们就不需要把全部数据查询一遍,而只需要找到对应列的位置,然后将这一连续空间的数据查询出来,进行聚合操作即可
    这样的存储方式,极大的方便了针对数值型字段聚合、重复度高的字段分组、需要排序的字段的查询操作
    并且联想一下,针对数值列,重复度高的列,我们还可以进行压缩操作,更加节约存储空间

    上述图形中,姓名、地址、学校这些字段也按列存储了,是不是造成浪费了?
    其实有这个问题,你大概率是陷入了误区,上述是为了给大家展示按列存储的物理结构,实际的操作时,我们是按需定义的,不要忘记这个属性是在field标签下的,也就是说他是针对某一列设置是否按列存储,所以如果不需要的字段,你不设置即可

    • multiValues: 字段值是否可重复,或者说是否为多个值,默认为false。一般用于数组字段

    比如如下的数据中,技能字段skills就是一个数组类型,就需要用multiValues=true标识

    {
      "name": "张三",
      "age": 28,
      "sex": "男",
      "address": "广州市xxx路",
      "school": "南京大学",
      "skills": [
          "Java",
          "Python",
          "C++",
          "数据结构与算法"
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    默认字段

    基于以上的属性我们就可以自定义字段了,但同时solr也提供了一些默认的字段,也称为域

        <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
     
        <field name="_version_" type="plong" indexed="false" stored="false"/>
    
        <field name="_root_" type="string" indexed="true" stored="false" docValues="false" />
      
        <field name="_nest_path_" type="_nest_path_" /><fieldType name="_nest_path_" class="solr.NestPathField" />
    
        <field name="_text_" type="text_general" indexed="true" stored="false" multiValued="true"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如上所示,其中包括:

    • id: 文档的唯一标识符,可以指定为数据源中的唯一索引字段
    • _version_: 版本号,用于并发控制,每次更新文档,版本值都会自动递增
    • _root_: 用于嵌套文档结构,表示潜逃文档所属的最外层文档
    • _nest_path_: 用于嵌套文档结构,表示嵌套文档在文档中的路径,可以根据该路径来查询嵌套文档
    • _text_: 文档的主要内容,用于全文检索

    假设有如下文档值:

    {
      "id": "001",
      "title": "Solr 学习笔记",
      "content": "这是一篇关于 Solr 的学习笔记,包含了 Solr 的介绍、安装、配置和使用等内容。"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    则对应的这几个字段的值是:

    {
      "id": "001",        // 文档唯一标识符
      "_version_": 1,     // 并发控制版本号
      "_root_": "001",    // 嵌套文档根节点(此处与id相同)
      "_nest_path_": "",  // 嵌套文档路径(顶级文档为空字符串)
      "_text_": [         // 全文检索内容
        "这是一篇关于 Solr 的学习笔记,包含了 Solr 的介绍、安装、配置和使用等内容。",
        "Solr 学习笔记"
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    比如有点赞信息时,就会引入嵌套文档

    {
      "id": "002",
      "title": "Solr 文档结构示例",
      "content": "这是一篇 Solr 文档嵌套结构的示例。",
      "_root_": "002",   // 根节点为自己
      "_nest_path_": "", // 初始情况下为空字符串
      "_text_": [
        "这是一篇 Solr 文档嵌套结构的示例。",
        "Solr 文档结构示例"
      ],
      "like": [          // 嵌套文档:点赞
        {
          "id": "u001",
          "user_name": "Tom",
          "_root_": "002",          // 父文档ID
          "_nest_path_": "/like",   // 嵌套路径为 /like
          "_text_": ["Tom"]
        },
        {
          "id": "u002",
          "user_name": "Jack",
          "_root_": "002",          // 父文档ID
          "_nest_path_": "/like",   // 嵌套路径为 /like
          "_text_": ["Jack"]
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    1.2 dynamicField 动态字段标签

    动态字段是用来做什么的?
    当我们出现部分字段名都是类似的,且表示相同的含义时,比如:name_1, name_2, name_3 ,如果有成百上千个这样的字段需要定义,还是很麻烦的,可能你觉得不会有这样的场景,但是在搜索引擎的业务场景下,存在大批量字段是比较常见的事情。

    这个时候,我们就希望能有一个类似通配符匹配配置的模式,来帮助我们批量定义字段,于是就出现了动态字段,比如上述的name_1, name_2, name_3 我们就可以定义为:

    <dynamicField name="name_*"  type="pint"  indexed="true"  stored="true"/>
    
    • 1

    动态字段只能有前缀和后缀两种匹配模式,用*来表示

    同时需要注意,在solr中,只有在managed-schema文件中配置过的字段,才能在查询时使用,这与数据库的逻辑是一致的,没有定义过的字段,直接使用就会报错"字段未找到"

    1.3 uniqueKey 唯一主键标签

    solr中默认使用id作为唯一主键,更新和新增时就通过唯一主键是否存在来决定

    1.4 copyField 复制字段标签

    复制字段的意思就是将一个或多个字段的值填充到另一个字段中,主要用来:

    • 将多个字段填充到一个字段方便搜索;

    如果目标字段中已经有自己的数据,那么会把复制字段的内容作为附加值添加到目标字段的内容中,从而实现更加全面的搜索覆盖

    <copyField source="name" dest="search_total"/>
    <copyField source="content" dest="search_total"/>
    <copyField source="title" dest="search_total"/>
    
    • 1
    • 2
    • 3
    • 对同一个字段定义不同的分词器,用于不同的搜索场景

    比如将某字段值,定义英文分词器,中文分词器,西巴牙语分词器,以应对不同语种的搜索场景

    <copyField source="name" dest="name_english"/>
    <copyField source="name" dest="name_chinese"/>
    
    • 1
    • 2

    1.5 fieldType 字段类型标签

    filedType标签主要用于定义字段的分词器、过滤器,实现为不同字段定义不同的分词、过滤器

    相当于是定义一个字段类型,然后在类型中指定使用的类,然后在field标签中就可以直接使用这个自定义的类型

    如下示例,就定义了一个类型my_text,定义了两个分析器,一个用于索引(index),一个用于查询(query),都是用StandardTokenizerFactory作为默认的分词器,StopFilterFactory作为过滤器,分别用于去除标点和停用词。不同的是查询时额外使用了SynonymGraphFilterFactorysynonyms.txt获取同义词

    PS:

    1、solr有哪些分词器和过滤器,我们将在后续讲解,或者大家也可自行拓展搜索,中文中还有常用的中文分词器——IK分词器
    2、不清楚同义词、过滤器、停用词作用的,因为是搜索引擎的基础概念,大家可自行搜索,如果仍不清楚,可留言提问

    <fieldType name="my_text" class="solr.TextField" positionIncrementGap="100">
      <analyzer type="index">
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
        <filter class="solr.LowerCaseFilterFactory"/>
      analyzer>
      <analyzer type="query">
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
        <filter class="solr.SynonymGraphFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true" />
        <filter class="solr.LowerCaseFilterFactory"/>
      analyzer>
    fieldType>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    filedType标签中常用的属性如下:

    • name: 定义类型名称
    • class: 定义类型使用的class类,比如text类型的用的就是solr自带的TextField类
    • positionIncrementGap 属性指定了位置增量间隔,用于多值字段在索引中处理位置信息,默认是0,也就是每个分词之间存储的间隔

    默认为0的话,比如这样的文档:

    <doc>
    	<filed name="id">1</field>
    	<filed name="content">wu quick study</field>
    	<filed name="content">solr study</field>
    </doc>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如果针对content字段设置的fieldType指定了默认positionIncrementGap=0,那么content的位置编号就是:

    位置编号文本
    1wu quick study
    2solr study

    如果设置的positionIncrementGap=10,则位置编号为,及文本不是连续存储的

    位置编号文本
    1wu quick study
    11solr study

    设置positionIncrementGap的好处和坏处?
    设置后可以控制多值字段不同值之间的位置增量,这样solr可以更加准确的计算匹配文档和查询相关度,从而计算结果排名,简言之就是查询的结果排名计算更加准确。当然他的坏处就是占用的空间变大,使得索引变大,那么查询性能就受到影响了

    其次,fieldType也支持filed中的以下标签:

    indexed:是否可以被索引,默认为 true。
    stored:是否可以被存储,默认为 true。
    multiValued:是否为多值字段,默认为 false。
    docValues:是否启用 DocValues,默认为 false。
    termVectors:是否启用 TermVectors,默认为 false。

    2. 总结

    今天,我们针对schema标签的详解就到此结束了,是不是感觉标签属性很多,记不过来,其实没关系,实际使用部分标签是用不到的,我们还可以根据模版参考配置,无需专门背诵,根据实际场景,多写几遍,自然就记住了

  • 相关阅读:
    【计算机视觉】 摄像机标定
    基于SSM的美食网站设计设计与实现-计算机毕业设计源码+LW文档
    基于小脑模型神经网络轨迹跟踪matlab程序
    R语言ggplot2可视化:gganimate包基于transition_time函数创建动态散点图动画(gif)
    想通过培训转行软件测试可以吗
    2.14日学习打卡----初学Zookeeper(一)
    正则验证用户名和跨域postmessage
    js如何判断设备类型(是否可以触屏)
    【跨境电商】6种实用有效的策略帮助改善客户沟通
    对Mysql中redo log、undo log、binlog深入理解
  • 原文地址:https://blog.csdn.net/qq_24950043/article/details/130793603