schema.xml配置

schema.xml用来定义文档的结构。一个文档有一个或多个域组成,而域又需要由不同的域类型进行定义。并且在创建索引的过程中,solr又需要对域进行分词。以下讲一一对以上内容进行说明。schema还分为三种:手动模式,自动模式和无schema模式。

域类型

域类型定义了应该如何从域中解析数据以及域是怎样被查询的。

  • name: 域类型的名称,强制性必须指定的,且必需保证同一个schema文件内唯一性;
  • class:域类型对应的Java类,强制性必须指定的,如果是solr内置的域类型,使用solr.类名方式指定即可,如果是自定义的域类型,必须指定类的完整路径;
  • positionIncrementGap: 配置多值之间的间隙,用于组织伪短语匹配,此配置适用于多值域;
  • autoGeneratePhraseQueries:若设置为true,solr会自动为相邻的term生成短语查询,若设置false,term必须被一对双引号包裹才能被认为是一个短语查询,此设置针对TextField;
  • docValuesFormat:配置DocValuesFormat实现,这个配置需要提前在solrconfig.xml中配置SchemaCodecFactory;
  • postingsFormat:postingFormat表示用于编/解码term,postings,数据的实现类,这个配置需要提前在solrconfig.xml中配置SchemaCodecFactory;
  • 配置域类型为TextField,则还需要配置<analyzer>元素来指定分词器;
  • 域类型属性依赖于具体实现类;
 <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100">
      <analyzer type="index">
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
        <!-- in this example, we will only use synonyms at query time
        <filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
        -->
        <filter class="solr.LowerCaseFilterFactory"/>
      </analyzer>
      <analyzer type="query">
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
        <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
        <filter class="solr.LowerCaseFilterFactory"/>
      </analyzer>
    </fieldType>

Solr内置预定义域类型

  • BinaryField:表示经过base64编码的字符串域类型,你需要吧binary数据进行base64编码才能被solr进行索引;
  • BoolField:表示boolean类型的数据,除了true,false,第一个字符是“1”,“t”,“T”也会被认为true;
  • CollationField:支持Unicode排序规则进行排序和区间范围查询,当你使用ICU4J时,选择使用ICUCollationField是更好的选择;
  • CurrencyField:支持货币以及货币兑换和货币汇率换算;
  • DateRangeField:支持对日期范围进行索引,从而支持日期范围查询;
  • ExternalFileField:对外部文件进行索引的域类型,他支持从外部硬盘上读取指定文件的内容创建索引;
  • EnumField:对枚举进行索引的域类型;
  • ICUCollationField:支持Unicode排序规则进行排序和区间范围查询;
  • LatLonType:用于对经纬度数据进行索引,经纬度数据格式必须为latitude,longitude,纬度在前,经度在后,两者之间用逗号隔开,且两者之间不能有空格等其他字符,且不支持多值。适用于solr中spatial search(空间查询);
  • PointType:支持对N个纬度的坐标定数据的索引,比如数学里的二维坐标x,y,甚至立体几何的三位坐标x,y,z,但不支持多值;
  • PreAnalyzedField:即预分词域,他提供一个序列化的token stream传递给solr,这样solr 在对PreAnalyzed-Field创建索引时不需要进行分词了,因为如何分词处理已经提前在序列化的token stream中定义好了;
  • RandomSortField:这个域类型不包含域值,他用于查询时,根据RandomSortField排序时,将会对返回结果进行随机排序,一般与dynamicField搭配使用;
  • SpatialRecursivePrefixTreeFieldType:用于深度便利前缀树的FieldType,主要用于获取lucene中的RecursivePrefixTreeStrategy。这个域用于solr中的Spatial Search(空间查询);
  • StrField:对UTF-8编码的字符串或者Unicode字符进行索引,StrField不会分词,且StrField有个硬性限制,字符大小必须小于32KB。他支持docValues域,但当为其添加了docValues域,则要求只能是单值域且该域必须存在或者该域有默认值;
  • TextField:用于对长文本进行索引,域StrField最大区别是,TextField会分词且无长度限制;
  • TrieDateField:Date域类型,表示一个毫秒精度对时间点,启用precisionStep=“0”会提升Date域对排序性能并最大限度的减少索引大小,配置precisionStep=“8”会提升Date域的范围区间查询性能;
  • DateRangeField:用于对日期范围进行索引,并且兼容TrieDateField;
  • TrieDoubleField:Double域类型,precisionStep=“0”会提升Double域的排序性能并最大限度减少索引大小,配置precisionStep=”8“会提升Double域的范围查询性能;
  • TrieFloatField:Float域类型,同TrieDoubleField类似;
  • TrieIntField:Integer域类型,同TrieDoubleField类似;
  • TrieLongField:Long域类型,同TrieLongField类似;
  • TrieField:如果你使用这个域,那么还需要指定一个type属性,他的可选值为integer,long,float,double,date。使用这个域跟使用TrieXXXField是一样的;
  • UUIDField:UUID域,如果域值为空字符串,或者null或者字符串“NEW”,那么solr会自动生成UUID字符串并创建索引,如果用户设置了域值,那么solr会首先检查域是否符合UUID规范,如果不符合,会抛出异常,否则会将域值转换为小写形式,最后穿件索引。在solrcloud环境下,配置一个UUIDField并且指定域值为“NEW”是不建议的,此时建议是用UUIDUpdateProcessorFactory来代替;

几个重点域类型讲解

  1. CurrencyField:
    提供对货币值的支持,solr可以在查询时使用他完成货币的兑换和货币汇率换算,该域支持以下功能:
  • 区间范围查询
  • Function区间范围查询
  • 排序
  • 货币代号以及货币符号(比如美元的$,人民币的¥)的解析
  • 支持对称和非对称汇率

配置案例1:通过FileExchangeRateProvider加载currencyConfig.xml配置文件
schema.xml配置

<fieldType name="currency" class="solr.CurrencyField" precisionStep="8" defaultCurrency="USD" currencyConfig="currency.xml" />

currency.xml内容

<currencyConfig version="1.0">
  <rates>
    <!-- Updated from http://www.exchangerate.com/ at 2011-09-27 -->
    <rate from="USD" to="ARS" rate="4.333871" comment="ARGENTINA Peso" />
    <rate from="USD" to="AUD" rate="1.025768" comment="AUSTRALIA Dollar" />
    <rate from="USD" to="EUR" rate="0.743676" comment="European Euro" />
    <rate from="USD" to="BRL" rate="1.881093" comment="BRAZIL Real" />
    <rate from="USD" to="CAD" rate="1.030815" comment="CANADA Dollar" />
    <rate from="USD" to="CLP" rate="519.0996" comment="CHILE Peso" />
    <rate from="USD" to="CNY" rate="6.387310" comment="CHINA Yuan" />
    <rate from="USD" to="CZK" rate="18.47134" comment="CZECH REP. Koruna" />
    <rate from="USD" to="DKK" rate="5.515436" comment="DENMARK Krone" />
    <rate from="USD" to="HKD" rate="7.801922" comment="HONG KONG Dollar" />
    <rate from="USD" to="HUF" rate="215.6169" comment="HUNGARY Forint" />
    <rate from="USD" to="ISK" rate="118.1280" comment="ICELAND Krona" />
...
</rates>
</currencyConfig>

配置案例2:通过OpenExchangeRatesOrgProvider调用远程接口获取汇率数据

<fieldType name="currency" class="solr.CurrencyField" precisionStep="8" providerClass="solr.OpenExchangeRatesOrgProvider" refreshInterval="60" ratesFieldLocation="http://www.openexchangerates.org/api/latest.json?appid=your-personalAppIdKey"/>
  • providerClass:表示provider实现类,内置的provider只需以solr.开头来代替默认包名即可,如果自定义实现的provider类,则需要指定完整包路径;
  • refreshInterval:表示每间隔多少分钟在重新从远程接口获取一次汇率数据;
  • ratesFileLocation:获取货币汇率数据的远程接口URL;
  1. TrieDateField:
    用于对日期时间类型数据进行索引,日期时间类型数据在Java里可以使用java.util.Date,Long,Integer来表示,Long、Integer类型可以表示毫秒数;使用时需要遵循以下格式约束:YYYY-MM-DDThh:mm:ssZ
  • YYYY表示年份
  • MM表示月份,两位数字表示
  • DD表示日期,两位数字表示
  • hh表示小时数,24小时制
  • mm表示分钟数
  • ss表示秒数
  • Z表示UTC时区

solr对于日期时间存储只能精确到毫秒,任何超出毫秒经度部分的数据将会被丢弃,因此如果需要精确到毫秒,那么日期时间数据格式应该类似如下:

1972-05-20T17:33:18.772Z
1972-05-20T17:33:18.77Z
1972-05-20T17:33:18.7Z

可以通过以下代码将以上日期时间转换成Date对象:

String input = "1972-05-20T17:33:18.772Z";
TimeZone utc = TimeZone.getTimeZone("UTC");
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
f.setTimeZone(utc);
GregorianCalendar cal = new GregorianCalendar(utc);
cal.setTime(f.parse(input));
Date date = cal.getTime();

一个TrieDateField域类型完整配置如下:

<field name="Date" class="solr.TrieDateField" datetimeformat="yyyy=MM-dd'T' HH:mm:ss.sss'Z'" indexed="true" multivalued="false" stored="true" precisionStep="6" type="date">
</field>
  • name:表示域类型的名称
  • class:表示域类型的实现类
  • detetimeformat:表示TrieDateField域的与之最终现实的字符串格式
  • indexed:表示是否对当前TrieDateField域创建索引
  • multivalued:表示是否为多值域
  • stored:表示是否存储域值
  • type:表示TrieDateField域的原始域值的数据类型,可选值:INTEGER,LONG,FLOAT,DOUBLE,DATE
  • precisisonStep:该属性值越大,生成的term个数越少,索引体积也会小,但区间范围查询性能也越低;反之,生成的term个数越多,索引体积越大,范围区间查询性能越高。如类型为Integer,则占4个字节32位,步长precisionStep=4时,那么生成这些term,前4bit,前8bit,前12bit,前16bit...直到32bit。
  1. DateRangeField:
    该域类型与TrieDateField类似,唯一的区别在于,该类型会以String类型暴露域值而非Date类型。
    使用该域类型时,日期范围字符串必须类似如下:[2000 TO 2014-05-21T17:33:18.772Z],并支持日期范围的多值域索引。
    案例:查询出某个时间段内正开放经营的餐厅。需要注意的是,每个餐厅在一天之内可以有多个开放时间,而且每天的开放时间不固定。
<field name="openingHours" type="date_range" indexed="true" stored="true" multiValued="true"/>
<fieldType name="date_range" class="solr.DateRangeField"/>

date_range域的数据:

[
"[2016-02-01T03:00Z TO 2016-02-01T15:00Z]",
"[2016-02-02T03:00Z TO 2016-02-02T15:00Z]",
"[2016-02-03T03:00Z TO 2016-02-03T15:00Z]",
"[2016-02-04T03:00Z TO 2016-02-04T15:00Z]",
"[2016-02-05T03:00Z TO 2016-02-05T16:00Z]",
"[2016-02-06T03:00Z TO 2016-02-06T16:00Z]"
]

可以通过如下查询:facet.range=openingHours&f.openingHours.facet.range.start=NOW&f.openingHours.facet.range.end=NOW%2B6HOUR&f.openingHours.facet.range.gap=%2B1HOUR

  • facet.range:表示你需要对哪个域进行区间查询
  • facet.range.start:表示查询区间的起始值
  • facet.range.end:表示查询区间的结束值
  • facet.range.gap:表示区间递增的间隙

4.EnumField:
该域类型用于对枚举类型的数据进行索引。

public enum LogLevel {
INFO,
DEBUG,
WARING,
ERROR
}

EnumField配置

<fieldType name="logLevelType" class="solr.EnumField" enumsConfig="enums-Config.xml" enumName="logLevel"
  • enumsConfig:用于指定枚举配置文件,在其中定义支持的所有枚举值
  • enumName:表示枚举名称,他必须域枚举配置文件中配置的某一个<enum>元素的name属性保持一致
<?xml version="1.0"?>
<enumsConfig>
 <enum name="logLevel">
<value>INFO</value>
<value>DEBUG</value>
<value>WARNING</value>
<value>ERROR</value>
</enum>
<enum name="priority">
<value>HIGH</value>
...
</enum>
...
</enumsConfig>
  1. ExternalFileField:
    该域类型支持为某个域指定域值,而该域值是从外部文件加载得到的。也就是说,某个域的与之不需要存储到Solr中,可以从外部文件获取。ExternalFileField是不支持查询的,它只能用于function query或者显示。
    案例:假设你的Document有一个views域,而这个views域可能表示的是一篇博客的浏览量,由于浏览量可能每分每秒都在改变,你可能希望每个1分钟或者半小时单独更新下views表示浏览量的域,而文档其他域的值可能更新并不是那么频繁。
<fieldType name="viewsFile" keyField="id" defVal="0" stored="false" indexed="false" class="solr.ExternalFileField" valType="pfloat"/>
  • keyField:定义唯一性标示域的名称,它通常示Document的唯一主键域,但并不是必须的,只要keyField能唯一标示一个Document即可
  • defValue:表示当某个Document在外部文件中不存在示,ExternalFileField的域值采用defVal定义的默认值
  • valType:定义需要在外部文件里加载的域值的时机数据类型,可选值为pfloat,float,tfloat,这个属性示可选的,可以不用配置
  • ExternalFileField依赖的外部文件默认需要存放在$SOLR_HOME/data目录下,文件名称应该满足如下规则:external_filename或者external_fileanme.*
    eg.external_entryRankFile或者external_entryRankFile.txt。如果匹配到多份文件,以最后一份为准。
    文件内容如下:
1=1000
2=20000
3=999

左边表示keyField参数表示的域的域值,右边表示需要存储到外部文件而且经常需要更新的域的域值。至此,我们只需要在field定义里通过type=“viewsFile”来应用ExternalFileField,之后更新veiews域的域值就不需要更新每一份Document而只需周期性更新外部文件的键值和对应的数值即可。

  1. UUIDField:
    使用场景:
  • 当你需要增量式的添加索引文档,索引文档可能会重复添加,而你不希望索引文档出现初伏
  • 当你的索引的数据很大,可能不会把它存储到solr索引中,但有希望后续能够根据索引中的某个域从外部数据源再次加载该数据
  • 当你希望更简便的使用唯一主键来删除一个文档,而不是每次都繁琐的使用query来匹配待删除文档
  • 当你是用DistributedSearch(分布式查询)时,需要一个唯一键来过滤多个分片上返回的重复文档,因为你不希望将重复的文档返回给用户。

UUID配置:

<!--schema.xml-->
<fieldType name="uuid" class="solr.UUIDField" indexed="true" />
<field name="id" type="uuid" indexed="true" stored="true" multiValued="false" required="true"/>

经过上面步骤,我们的UUIDField域已经配置好了,但solr还提供了一个自动更新UUIDField的处理器,也就是使用它UUIDUpdateProcessorFactory,我们就不需要关心如何创建和更新UUIDField域了,全权交给UUIDUpdateProcessorFactory处理就行了。

<!--solrconfig.xml-->
<updateRequestProcessorChain name="dispup">
<processor class="solr.UUIDUpdateProcessorFactory">
<str name="fieldName">id</str>
</processor>
<processor class="solr.LogUpdateProcessorFactory"/>
<processor class="solr.DistributedUpdateProcessorFactory"/>
<processor class="solr.RunUpdateProcessorFactory"/>
</updateRequestProcessorChain>
<requestHandler name="/update" class="solr.UpdateRequestHandler">
<lst name="defaults">
<str name="update.chain">dispup</str>
</lst>
</requestHandler>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容

  • schema.xml位于core目录/conf/目录下,用于配置该core中的字段即字段类型,处理、分析方式。主要...
    熊颀阅读 2,956评论 0 0
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,300评论 0 9
  • 1.schema.xml是干什么用的? Schema.xml 作为 MyCat 中重要的配置文件之一,管理着 My...
    Johnny_Kam阅读 13,636评论 1 4
  • Solr可以看作是一个非关系型数据库,数据是保存在schema中,而每个schema里面的列就是filed。Fie...
    尚亦汐阅读 1,778评论 0 1
  • 妈妈的怀抱拥着一束暖光 点亮稚子 纯善澄明的眸,望向 幻影婆娑陆离光怪的窗口 斑斓曦辉 那片混沌的小世界瞬息明朗灵...
    吹面不寒杨阅读 718评论 4 12