solr搭建电商搜索引擎03 - 配置solrconfig和schema

利用solr构建搜索引擎,我们需要“新建core——配置文件——索引数据”三个步骤才能实现基本的查询,在此基础上还需要继续研究查询解析、中文分词、排序、分面、高亮等功能,才能实现一个成熟的搜索。当然,配置文件的修改是伴随我们功能的开发不断进行的。

1 配置solrconfig文件

前面介绍过,solrconfig的作用是配置索引创建、查询、solr缓存以及solr组件处理器,这里我们对solrconfig的修改主要是变更schema的模式:

<schemaFactory class="ClassicIndexSchemaFactory"/>;

注意,在变更schema模式后,我们需要把managed-schema的文件名改为schema。

2 配置schema文件

2.1 schema文件的结构

当我们把数据传递给solr时,solr要按照我们预先设定的模式对这些数据进行处理,如字段的类型、字段的用途、字段的分词方法等(solr中把字段定义为域,即field),而这些模式就是我们通过schema设定的。在schema中,我们需要在solr内置的预定义域类型的基础上(class,本质是java类)定义我们自己的域类型(fieldtype),然后利用域类型去定义域(field),以一个简单的schema例子来说明:

  • Line 1、Line 2:定义schema的版本、编码和名称等;
  • Line 3:定义了一个名称为“long”的域类型,继承了solr的预定义域类型“solr.TrieLongField
    ”,并且为该域类型设定了“precisionStep”和“positionIncrementGap”两个参数;
  • Line 4:配置“id”域作为文件的唯一标识,solr会根据该域决定增量导入或重复导入;
  • Line 5、Line 6:定义了两个名称为“id”和“series_code”的域,域类型为我们刚创建的“long”,并且为该域设定了“indexed”和“stored”两个参数;
  • Line 5:schema设定结束。
<?xml version="1.0" encoding="UTF-8" ?>
<schema name="example" version="1.5">
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<uniqueKey>id</uniqueKey>
<field name="id" type="long" indexed="true" stored="true"/>
<field name="series_code" type="long" indexed="true" stored="true"/>
</schema>

2.2 域类型的定义(fieldtype)

<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>

如之前的schema例子,域类型的定义一般需要name、class和properties三类信息:

  • name:域类型的名称,必须指定,且要保证schema文件内的唯一性;
  • class:域类型继承的solr的预定义域类型,必须指定,内置的域类型以solr为前缀,具体如下(部分):
域类型描述
solr.BoolField布尔类型
solr.TrieDateField日期类型
solr.TrieIntField整数类型
solr.TrieLongField长整数类型
solr.TrieFloatField浮点数类型
solr.TrieDoubleField双精度浮点数类型
solr.StrField字符串类型,不分词
solr.TextField长文本类型,需要设置分词器
  • properties:域类型的属性一般取决于class,但是也有一些属性是通用的(部分):
域类型属性描述
positionIncrementGap设定多值之间的间隙,适用多值域
autoGeneratePhraseQueries是否自动为相邻term生成短语查询,默认true

2.3 域的定义(field)

<field name="series_code" type="long" indexed="true" stored="true"/>

如之前的schema例子,域的定义一般需要name、class、default和properties四类信息:

  • name:域的名称,必须指定,且要保证schema文件内的唯一性;
  • class:域的类型,必须指定,且要能够在fieldtype的name属性中找到;
  • default:域的默认值,可以不指定,索引时如没有赋值则使用默认值;
  • properties:域的属性,域和域类型有很多相同的配置属性(如下表),这些属性可以同时在定义域类型和定义域的时候指定,但定义域中的参数优先级更高。
域属性描述
indexed是否需要索引,默认true,配置为true时才能被查询
stored是否需要存储,默认true,配置为true时才能被抽取
compressed是否压缩域值,默认false,适用字符串和长文本,且stored为true时有效
multiValued是否为多值域,默认false
required是否必需,默认false,配置为true时文件必须含该字段才能被索引

除了以上域的定义外,还有一些特殊的方法:复制域,动态域和文本域。

2.3.1 复制域

我们在构建搜索功能的时候,可能需要对同一个字段进行不同的处理,比如调用两个不同的分词模块对文本进行分词;又或者需要把多个不同字段的数值汇聚成新字段,比如我们想把商品的名称、型号和品牌汇聚成一个多值字段用于搜索。在这两种情况下,我们就需要用到solr的复制域。

<field name="goods" type="string" index="true" stored="false" multiValues="true" />
<copyField source="series_name" dest="goods" />
<copyField source="series_code" dest="goods" />
<copyField source="brand_name" dest="goods" />

如上所示,我们首先定义了一个字段“goods”,然后分别从“series_name”,“series_code”和“brand_name”三个字段复制到了“goods。”有两点需要我们注意:第一,solr不会返回复制字段的数值,即stored只能是false(来源字段不受影响);第二,如果来源字段是多值域或者有多个来源字段,复制字段都应设定为多值域。

2.3.2 动态域

根据solr的索引机制,只有schema中定义的域才能被索引,这就意味当业务变更时我们必须在schema中追加域并频繁的加载,而动态域则可以让域的定义不再那么死板。简单来说,动态域定义了一个具有特定前缀或后缀的name的域,当我们索引文档的时候,如果solr没有找到对应的域,那么就会根据模糊匹配继续寻找对应的动态域。基于动态域,我们可以更灵活的应对以下场景:

  • 相同属性的域:如果商品信息具有长度、宽度、重量等属性相同的整数域,我们可以定义一个动态域“_num”,然后在索引数据的时候使用动态域“length_num”,“width_num”和“weight_num”;
  • 临时追加的域:如果商品信息经常出现新的字段如“面积”、“半径”等,我们可以定义一个动态域“_att”,然后在索引数据的时候使用动态域“area_att”和“radius_att”。

如下所示,我们定义了一个“_s”后缀的动态域,这样当我们索引数据时就可以直接使用“f1_s”、“f2_s”等类似域名。

<dynamicField name="*_s" type="string" index="true" stored="true"/>

2.3.3 文本域

文本域的定义方法我们前面已经讲过,这里再次介绍的原因是和整数域、字符串域相比,文本域需要额外配置分词器(这里默认大家对倒排索引和中文分词已经有了基本认识)。solr的分词器Analyzer包括两个核心组件Tokenizer和TokenFilter,前者用于生成Token流,后者用于对Token流进行过滤(可以没有)。

以下是一个完整的文本域定义方法。我们首先定义了域“series_name”,域类型是“solr.TextField”。接着为该文本域配置了分词器“analyzer”,包括一个Tokenizer和两个TokenFilter。solr内置了很多分词器,我们可以用下面类的方法直接调用,但还有很多第三方的中文分词包则需要进行更复杂的配置,但schema中的定义方法都是一样的。分词器的具体配置和使用方法我们后续再讲。

<fieldType name="series_name" class="solr.TextField" positionIncrementGap="100">
<analyzer>
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>

2.4 完整的schema样例

<?xml version="1.0" encoding="UTF-8" ?>
<schema name="example" version="1.5">

<!-- common fieldType -->
<fieldType name="string" class="solr.StrField" sortMissingLast="true"/>
<fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
<fieldType name="int" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="date" class="solr.TrieDateField" precisionStep="0" positionIncrementGap="0"/>
<!-- text fieldtype -->
<fieldType name="text_cn_index" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="false">
<analyzer>
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
<!-- text fieldtype -->
<fieldType name="text_cn_fulltext" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="false">
<analyzer>
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
<!-- field -->
<field name="_id_" type="string" indexed="true" stored="true"/>
<field name="_root_" type="string" indexed="true" stored="false"/>
<field name="_version_" type="long" indexed="true" stored="true"/>
<uniqueKey>product_id</uniqueKey>
<field name="product_id" type="long" indexed="true" stored="true"/>
<field name="product_name" type="text_cn_index" indexed="true" stored="true"/>
<field name="product_code" type="string" indexed="true" stored="true"/>
<field name="order_code" type="string" indexed="true" stored="true"/>
<field name="product_price" type="float" indexed="true" stored="true"/>
<field name="product_brand" type="text_cn_index" indexed="true" stored="true" multiValued="true"/>
<field name="product_unit" type="string" indexed="true" stored="true"/>
<field name="product_days" type="int" indexed="true" stored="true"/>
<field name="product_rank" type="int" indexed="true" stored="true"/>
</schema>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值