企业级搜索引擎Solr 第二章 Schema和文本分析(Schema and Text Analysis)[2]

2019-03-27 01:17|来源: 网路

文章转载自网易博客,原文地址:http://quweiprotoss.blog.163.com/blog/static/40882883201271714914811/

 

Schema and Text Analysis

Author: David Smiley Eric Pugh

译者:Koala++ / 屈伟

 

The schema.xml file

         我们最终来看Solr Schema

         在我们开始之前,你先找到schema.xml文件。这个文件在一个Solr实例的conf目录下。它在Solrexample/solr/conf/schema.xml位置。这个示例schema.xml中有一些有用的域类型,以及详细的说明,和为示例数据的域定义。

         schema.xml文件开始处有:

<schema name="musicbrainz" version="1.4">

         我们设置schemamusicbrainz,即我们应用的名字。如果我们用不同的schema文件,我们可以将它们命名不同的名字以区别它们。

Defining field types

         Schema配置文件第一部分是配置域的数据类型。这部分到</types>结束,这部分配置占了文件的相当多一部分内容。域类型声明了域的数据类型,比如布尔,数值,时间,或是文本。这些定义会被<fields>中的域定义引用,下面是一个类型为boolean的域类型:

<fieldType name="boolean" class="solr.BoolField" sortMissingLast="true" omitNorms="true"/>

         一个域的类型有一个唯一的名字,并且这个类型是由class属性指定的一个Java类实现的。

         包括nameclass在内的大部分属性都适用于所有类型,比如omitNorms,也有一些属性只适用一些特定的类。它们通常可以在域声明的时候被覆盖。除了这些属性外,还有一些属性只适用于文本域。它们会在本章后来的内容介绍。

Built-in field type classes

         Solr有很多的内置域类型,几乎所有的类型都在Solr示例的schema.xml中有详细的介绍。这里我们不会一一列举它们,但是会详细介绍几个重要的域类型。

Numbers and dates

         Solr至少有五种不同的域类型来保存一个整型,如果你算上string类型,那就是六种!对floatdoublelongdate也是一样,也至少有五种类型。这也许和你想的Solr只处理文本的不一样。我后面会以Integer为例解释何时使用它们。以“Trie”开头的类型可以满足你95%的需求

l  tieIntField(有precisionStep=0),通常称为“int”。它对大部分应用场景都是适合的。

l  tieIntField(有precisionStep>0),通常称为“tint”。如果你想在很多值的域上进行数值区间查询(包括facet区间),那么这种域类型在查询时有着极好的性能,但需要在索引时多消耗一点索引空间和时间。 Solr的示例配置中数值类型的precisionStep设置为8date类型为6,我推荐你使用这种默认设置。因为如果你选择更小的precisionStep值(但>0),会导致Solr会为提高区间查询性能而增加索引的空间和时间。

l  srtableIntField,通常称为“sint”。与Trie相似,有precisionStep=0,这个类型还支持sortMissingFirstSortMissingLast属性。

l  intField,通常称为“pint”。这是一个旧的实现,请不要使用它。

l  BCDIntFIeldBinary Coded Decimal)。不会费神知道它是什么。

所有的数值类型都会以它们的数值排序而不是按字典序排序。

最后,还有一个域类型为ExternalFileField,它能从一个纯文本文件中,而不索引中读取float类型值。它是用于处理要进行排序或影响打分的域变化很快的情况的(比如,按投票或是点击率排序),用这种类型不用再对文档建索引。注意Lucene底层无法单独更新一个域,整个文档都需要重建索引。这是特殊情况的临时解决方法,在第五章,Search Relevancy还会再介绍。

Geospatial

         我们将在第四章来介绍它。

Field options

         下面介绍的属性适用于大部分域类型,但不是全部域类型。

l  indexed:表示这个域可以被搜索和排序。不被索引的域的唯一用途就是作为搜索结果返回。

?  sortMissingLastsortMissingFirst:如果设置这两个属性为true,会指定排序时域值为空时会排在前面或是后面,而不管是升序还是逆序排序。默认行为是缺失值的文档在升序排序时排在前面,而降序时排到后面。

?  omitNorms:(高级)如果你不想域值的长度影响得分(见第五章)或是它根本就不参与排序(比如用于faceting),如果你在索引时进行文档boosting(下章介绍),你可以设置它。除了它对得分的影响,它还可以节省一点内存。

?  omitTermFreqAndPositions:(高级)在索引时忽略词频和词的位置以节约一些空间。后果是词组索引不能使用并且得分准确性受影响。

?  termVectors:(高级)告诉Lucene保存一些信息以在某些情况下提升搜索性能。比如,一个域要用MoreLikeThis特征,或是高亮比较长的文本域,那么设置这个属性。它会极大地增加索引的大小和索引的时间,所以你要设置它,请进行设置前后的对比实验。还有两个属性termPositionstermOffsets会添加更多的信息到词向量中。FastVectorHighlighter需要这两个属性。

?  positionIncrementGap:(高级)对一个multiValued域,这是设置在两个域值之间有多少虚拟的词,这是为了防止词组匹配时意外匹配相邻的域值。比如,如果AB是一个域的两个值,如果positionIncrementGap设置大于1,那么词组匹配会阻止“AB”被匹配。

l  stored:表明这个域可以在搜索结果中出现。通常域是被存储的,但有时同一域会被拷贝到多个域分别存储,所以这个域不会被标记为stored

?  compressed:不再支持。这个选项从Solr v1.4被移除了。因为开发者对它的实现不满意。

l  multiValues:设置这个属性可以让一个域包含多个值。值的顺序是与输入时一致的。

Field definitions

         Schema中域的定义在<fields>元素内,除了上面描述的域的选项,一个域还可以有下面的属性:

l  name:唯一标识这个域的名字,名字的值在字符上没有限制,任何词都可以用,除了score

l  type:引用Schema前面定义的域值。

l  default:(可选)当文档中没有这个域的值时,所用的默认值。一个常用的设置文档时间戳的配置<fieldname="indexedAt" type="tdate" default="NOW/SECOND" />,在第四章DateMath会介绍更多关于date的内容。

l  required:(可选)设置为true,在文档中相应域没有值时,建索引会失败。

Dynamic field definitions

         动态域定义的概念,它展示了Lucene相比典型的关系数据库索引的灵活性,在Solr中你不但可以明确地指定域的名字,也可以直接使用建索引时文档中提供的名字。Solr的示例Schema中提供一个例子,如下:

<dynamicField name="*_dt" type="date" indexed="true" stored="true"/>

         如果在建索引的时候,如果一个文档中的一个域既与一个明确的域定义匹配,又与一个动态域定义模式匹配(比如update_dt,它匹配*_dt),那么会选择明确的域定义名字。动态域定义和普通域定义格式一样,但元素的名字是dynamicField,并且它的name属性必须以星号开头或是结尾。也可以只有*一个字符,表示匹配所有。

         最后,无论是明确定义的域或是动态定义的域,它都是域,动态定义域只是方便地定义schema的一种方式。动态定义域方式不会对性能造成影响。

Our MusicBrainz field definitions

         下面是我们的MusicBrainz Schema定义的第一部分。下面是有一些域为是后面章节介绍其它搜索属性而加入的。下面的配置是一个结合Schemacombined schema),它定义了所有的索引实体类型:artistsreleasetracks。定义的方法在本章前面的内容已经介绍过了。注意我在域的名字前加入加了实体名的前缀(a_r_t_),以避免与其它实体的域名冲突。我们还在denormalize的时候使用像这样的缩写域名r_a_name(一个ReleaseArtist的名字)。

<!-- COMMON TO ALL TYPES: -->

<field name="id" type="string" required="true" />

<!-- Artist:11650 -->

<field name="type" type="string" required="true" />

<!-- Artist | Release | Label -->

<field name="indexedAt" type="tdate" default="NOW/SECOND" />

<!-- ARTIST: -->

<field name="a_name" type="title" />

<!-- The Smashing Pumpkins -->

<field name="a_name_sort" type="string" stored="false" />

<!-- Smashing Pumpkins, The -->

<field name="a_alias" type="title" stored="false" multiValued="true"

/>

<field name="a_type" type="string" />

<!-- group | person -->

<field name="a_begin_date" type="tdate" />

<field name="a_end_date" type="tdate" />

<field name="a_member_name" type="title" multiValued="true" />

<!-- Billy Corgan -->

<field name="a_member_id" type="long" multiValued="true" />

<!-- 102693 -->

<!-- RELEASE -->

<field name="r_name" type="title" />

<!-- Siamese Dream -->

<field name="r_name_sort" type="string" stored="false" />

<!-- Siamese Dream -->

<field name="r_a_name" type="title" />

<!-- The Smashing Pumpkins -->

<field name="r_a_id" type="long" />

<!-- 11650 -->

<field name="r_attributes" type="int" indexed="false"

multiValued="true" />

<!-- ex: 0, 1, 100 -->

<field name="r_type" type="rType" stored="false" multiValued="true" />

<!-- Album | Single | EP |... etc. -->

<field name="r_official" type="rOfficial" stored="false"multiValued="

true" />

<!-- Official | Bootleg | Promotional -->

<field name="r_lang" type="string" indexed="false" />

<!-- eng / latn -->

<field name="r_tracks" type="int" indexed="false" />

<field name="r_event_country" type="string" multiValued="true" />

<!-- us -->

<field name="r_event_date" type="tdate" multiValued="true" />

<!-- TRACK -->

<field name="t_name" type="title" />

<!-- Cherub Rock -->

<field name="t_num" type="int" indexed="false" />

<!-- 1 -->

<field name="t_duration" type="int"/>

<!-- 298133 -->

<field name="t_a_id" type="long" />

<!-- 11650 -->

<field name="t_a_name" type="title" />

<!-- The Smashing Pumpkins -->

<field name="t_r_name" type="title" />

<!-- Siamese Dream -->

<field name="t_r_tracks" type="int" indexed="false" />

<!-- 13 -->

         注意我们指定required的域是对所有类型都通用的,即IDtype域,因为我们正在进行结合索引的Schema配置。

         在我们的Schema中我们选择对大部分域进行索引,尽管在MusicBrainz搜索中只能对每种实体的名字搜索。我们这样做是想让Schema变得更有趣一些,以展示更多的Solr的能力。

Copying fields

         与域定义紧密相关的配置是copyFieldcopyField配置在索引时将一个或多个输入域的值拷贝到另一个域。一个copyField配置如下:

<copyField source="r_name" dest="r_name_sort" maxChars="20" />

         在当你想将一个域的值以不同的方式索引时,这个配置就发挥它的作用了。比如,排序和Faceting需要单个索引值。在搜索技巧中另一个常用的方法是将多个域的值拷贝到一个域去,这个域不使用norm也不进行排序。这可以使搜索只搜索 一个域而不是多个域,从而在牺牲得分质量的代价下可以极大的提高搜索性能。这种技巧通常还会搜索另几个有着较高boost的域以弥补得分的影响。在本章后面介绍的dismax查询解析器,会使这变得容易。

         在索引的时候,输入数据中的每个域的名字都会与所有copyField配置中的域名比较。source属性可以会使用*通配符,所以输入数据的域可能会匹配多于一个copyField。如果通配符在destination中使用,则它必须引用的是一个动态域(dynamic field),并且这时source中也必须使用通配符,否则就会报错。一个匹配source属性指定域的值都会拷贝到dest属性中指定的域中。如果指定了可选maxChar属性,则最多拷贝配置值的字符数。拷贝不会覆盖dest域中的原有数据,所以如果要拷贝多个域,记得可能需求指定multiValued

The unique key

         在接近schema的最下面是<uniqueKey>声明,它指定每个文档的唯一ID,如果这个ID存在。下面是我们在MusicBrainz Schema中的配置:

<uniqueKey>id</uniqueKey>

         尽管这个配置不是强制要求的,但是你应该定义一个唯一ID域。在我们的MusicBrainz Schema中,ID是一个字符串,它有实体类型的前缀,所以是全局唯一的,比如Artist:11650。如果你的源数据中没有一个ID域,你可以考虑用Universally Unique Identifier,一个遵循RFC-4122标准的UUID。你只需要有一个class属性值为solr.UUIDField的域类型的域,或是将域的defaultField的值为一个特殊值“NEW”,这样Solr就会自动产生UUIDSolrUUID是基于java.util.UUID的。

The default search field and query operator

         在接近Schema文件的底部有两个配置元素指定在解析一个查询字符串时域默认的搜索行为:

<!-- <defaultSearchField>text</defaultSearchField>

<solrQueryParser defaultOperator="AND"/> -->

         其中defaultSearchField指定了如果查询中没有明确指定要查询的域时默认的查找域。而solrQueryParser配置中的defaultOperator属性可以让你指定默认的搜索操作(AND或是OR)。这些对于Solr请求处理器处理查询时是非常重要的默认值。我强烈建议你忽略solrQueryParserdeaultOperator属性,也不要依赖defaultSearchField。这些配置可以在solrconfig.xml中进行配置。

 

上一篇:

企业级搜索引擎Solr 第二章 Schema和文本分析(Schema and Text Analysis)[1]

下一篇:

企业级搜索引擎Solr 第二章 Schema和文本分析(Schema and Text Analysis)[3]

 


转自:http://blog.csdn.net/shouzaihui/article/details/9818385

相关问答

更多
  • 运行教程计数以获得推文中的正面词汇总和给出了753次点击,而不是1105。 你的列表理解是正确的。 但是,教程按空格分割推文,然后计算整个单词 : >>> for tweet in tweets_list: ... positive_counter=0 ... tweet_processed=tweet.lower() ... for p in list(punctuation): ... tweet_processed=tweet_processed.replace ...
  • 没有更多的回答有点困难,这更像是一个上下文问题而不是代码问题。 但是这里是用来开始评估这个问题的逻辑。请记住,它可能涉及编写一些单独的脚本,每个脚本执行一部分任务。 尝试将问题分解成更小的部分。如果没有所有数据,您无法进行分析,因此首先要创建数据。 您已将类别和子类别列入每个列表中的所有唯一因子,并根据您的系统和业务需求为每个因素创建一组权重。 在制作子类别权重时,请记住它们将如何与类别(+/-以及幅度)进行交互。 写一个脚本来阅读描述,计算所有非平凡的单词。 为单词创建某种分类,以帮助您构建将使用类别和子 ...
  • 有条目的十大公司(以及每个公告的通知数量) :面对公司,做一个: -搜索。 如果每个通知都有一个文档,您将在分面请求中获得所需的结果。 每年公布的通知数量 :在日期时间范围内以年份为间隔。 发布通知的最多和最不受欢迎的日/月 :为日期和月份添加两个显式字段,并在这些字段上添加facet。 也许你也可以在工作日编制索引吗? 发布通知当天最受欢迎的小时 :制作一个仅包含小时的字段,其中包含方面。 最长的通知(按字符数) :函数查询是这里的候选者,但是没有strLength函数。 此外,它不适用于您使用文本字段的 ...
  • 如果你真的想学习这个话题,那么你可能需要一个标准的理论/算法教科书。 我不知道有任何网站可以真正教你复杂性分析(“复杂性”或“时间复杂性”就是你如何调用这些O()值;你可能还想谷歌的“算法分析”或“算法“等)。 但在此之前 - 一个免费的选择。 Erik Demaine和Charles Leiserson在麻省理工学院开设的课程中有幻灯片,免费且很好看。 我一定会尝试阅读它们,看看它是否适合你。 他们在这里 。 现在,教科书: 经典的教科书选择是Cormen等人的着作Introduction to Algo ...
  • 有关自然语言处理的教科书列表,请参阅此问题的答案。 此外, Lucene in Action是一本关于领先的全文搜索库的实用书。 同样, 清醒的想象力是一家新公司,拥有大量关于信息检索的文章库。 Please see my answer to this question for a list of textbooks regarding natural language processing. Also, Lucene in Action is a great practical book about a ...
  • 一些有用的链接开始于: http://alias-i.com/lingpipe/demos/tutorial/sentiment/read-me.html http://kmandcomputing.blogspot.com/2008/06/opinion-mining-with-rapidminer-quick.html http://rapid-i.com/content/blogcategory/38/69/ http://www.cs.cornell.edu/People/pabo/movie-re ...
  • Rizzoma.com用couchDB(noSQL)和Sphinx(全文搜索引擎)制作了这个。 如果需要,您可以尝试以其他方式创建它,或者测试现有解决方案并重复它。 Rizzoma.com made this with couchDB (noSQL) and Sphinx (fulltext search engine). You can try to make it in another way, if you want, or test existing solution and repeat it.
  • E(subCluster)$text不起作用,因为tweets$text的值在制作时不会添加到图形中。 所以你必须手动完成。 这有点痛苦,但可行。 需要一些tweets数据框的子集和基于用户名的匹配。 首先,请注意边缘类型按特定顺序:转发,提及,回复。 来自特定用户的相同文本可以应用于所有这三个。 所以我认为连续添加文本是有意义的。 > unique(E(g_twitter_actor)$edgeType) [1] "Retweet" "Mention" "Reply" 使用dplry和reshape ...
  • library(data.table) b <- data.frame(id = c('1','2', '3', '4'), Goods.Description = c("This green T-shirt can become...", "Stripes of unfaded denim at each side of this blue skirt make...", "Velvet's Brynna red top comes in a bohemian...", "The Riley blue ...
  • 忽略HappyTimeGopher提出的否定问题,您可以简单地将句子中的快乐单词数除以句子的长度。 你得到: 约翰很高兴。 (“快乐”中的1个单词/句子中的3个单词=快乐的成绩为33%) 约翰昨天告诉玛丽,他很高兴。 (1/8 = 12.5%快乐) 请记住,基于单词列表的方法只会到目前为止。 “我对食物感到满意,但服务员很可怕”的分数应该是多少? 考虑使用更复杂的系统---下面的论文是开始研究的好地方: Choi,Y。和Cardie,C。(2008)。 学习成分语义作为亚属情感分析的结构推理。 Moilan ...