现在我们开始研究载入的数据部分(importing data)
在正式开始前,我们先介绍一个存储了大量音乐媒体的网站http://musicbrainz.org ,
这里的数据都是免费的,一个大型开放社区提供。
MusicBrainz每天都提供一个数据快照(snapshot)的SQL文件,这些数据可以被导入PostgreSQL数据库中。
一、字段配置(schema)
schema.xml位于solr/conf/目录下,类似于数据表配置文件,
定义了加入索引的数据的数据类型,主要包括type、fields和其他的一些缺省设置。
1、先来看下type节点,这里面定义FieldType子节点,包括name,class,positionIncrementGap等一些参数。
< schema name = "example" version = "1.2" > < types > < fieldType name = "string" class = "solr.StrField" sortMissingLast = "true" omitNorms = "true" /> < fieldType name = "boolean" class = "solr.BoolField" sortMissingLast = "true" omitNorms = "true" /> < fieldtype name = "binary" class = "solr.BinaryField" /> < fieldType name = "int" class = "solr.TrieIntField" precisionStep = "0" omitNorms = "true" positionIncrementGap = "0" /> < fieldType name = "float" class = "solr.TrieFloatField" precisionStep = "0" omitNorms = "true" positionIncrementGap = "0" /> < fieldType name = "long" class = "solr.TrieLongField" precisionStep = "0" omitNorms = "true" positionIncrementGap = "0" /> < fieldType name = "double" class = "solr.TrieDoubleField" precisionStep = "0" omitNorms = "true" positionIncrementGap = "0" /> </ types > </ schema >
< fieldType name = "text_ws" class = "solr.TextField" positionIncrementGap = "100" > < analyzer > < tokenizer class = "solr.WhitespaceTokenizerFactory" /> </ analyzer > </ fieldType > < fieldType name = "text" class = "solr.TextField" positionIncrementGap = "100" > < analyzer type = "index" > <!--这个分词包是空格分词,在向索引库添加text类型的索引时,Solr会首先用空格进行分词 然后把分词结果依次使用指定的过滤器进行过滤,最后剩下的结果,才会加入到索引库中以备查询。 注意:Solr的analysis包并没有带支持中文的包,需要自己添加中文分词器,google下。 --> < tokenizer class = "solr.WhitespaceTokenizerFactory" /> <!-- in this example, we will only use synonyms at query time < filter class = "solr.SynonymFilterFactory" synonyms = "index_synonyms.txt" ignoreCase = "true" expand = "false" /> --> <!-- Case insensitive stop word removal. add enablePositionIncrements = true in both the index and query analyzers to leave a 'gap' for more accurate phrase queries. --> < filter class = "solr.StopFilterFactory" ignoreCase = "true" words = "stopwords.txt" enablePositionIncrements = "true" /> < filter class = "solr.WordDelimiterFilterFactory" generateWordParts = "1" generateNumberParts = "1" catenateWords = "1" catenateNumbers = "1" catenateAll = "0" splitOnCaseChange = "1" /> < filter class = "solr.LowerCaseFilterFactory" /> < filter class = "solr.SnowballPorterFilterFactory" language = "English" protected = "protwords.txt" /> </ analyzer > < analyzer type = "query" > < tokenizer class = "solr.WhitespaceTokenizerFactory" /> < filter class = "solr.SynonymFilterFactory" synonyms = "synonyms.txt" ignoreCase = "true" expand = "true" /> < filter class = "solr.StopFilterFactory" ignoreCase = "true" words = "stopwords.txt" enablePositionIncrements = "true" /> < filter class = "solr.WordDelimiterFilterFactory" generateWordParts = "1" generateNumberParts = "1" catenateWords = "0" catenateNumbers = "0" catenateAll = "0" splitOnCaseChange = "1" /> < filter class = "solr.LowerCaseFilterFactory" /> < filter class = "solr.SnowballPorterFilterFactory" language = "English" protected = "protwords.txt" /> </ analyzer > </ fieldType >
2、再来看下fields节点内定义具体的字段(类似数据库的字段),含有以下属性:
< fields > < field name = "id" type = "integer" indexed = "true" stored = "true" required = "true" /> < field name = "name" type = "text" indexed = "true" stored = "true" /> < field name = "summary" type = "text" indexed = "true" stored = "true" /> < field name = "author" type = "string" indexed = "true" stored = "true" /> < field name = "date" type = "date" indexed = "false" stored = "true" /> < field name = "content" type = "text" indexed = "true" stored = "false" /> < field name = "keywords" type = "keyword_text" indexed = "true" stored = "false" multiValued = "true" /> <!--拷贝字段--> < field name = "all" type = "text" indexed = "true" stored = "false" multiValued = "true" /> </ fields >
3、建议建立一个拷贝字段,将所有的 全文本 字段复制到一个字段中,以便进行统一的检索:
以下是拷贝设置:
< copyField source = "name" dest = "all" /> < copyField source = "summary" dest = "all" />
4、动态字段,没有具体名称的字段,用dynamicField字段
如:name为*_i,定义它的type为int,那么在使用这个字段的时候,任务以_i结果的字段都被认为符合这个定义。如name_i, school_i
< dynamicField name = "*_i" type = "int" indexed = "true" stored = "true" /> < dynamicField name = "*_s" type = "string" indexed = "true" stored = "true" /> < dynamicField name = "*_l" type = "long" indexed = "true" stored = "true" /> < dynamicField name = "*_t" type = "text" indexed = "true" stored = "true" /> < dynamicField name = "*_b" type = "boolean" indexed = "true" stored = "true" /> < dynamicField name = "*_f" type = "float" indexed = "true" stored = "true" /> < dynamicField name = "*_d" type = "double" indexed = "true" stored = "true" /> < dynamicField name = "*_dt" type = "date" indexed = "true" stored = "true" />
schema.xml文档注释中的信息:
1、为了改进性能,可以采取以下几种措施:
2、< schema name =" example " version =" 1.2 " >
3、filedType
< fieldType name =" string " class =" solr.StrField " sortMissingLast =" true " omitNorms =" true " />
positionIncrementGap:可选属性,定义在同一个文档中此类型数据的空白间隔,避免短语匹配错误。
name: 字段类型名
class: java类名
indexed: 缺省true。 说明这个数据应被搜索和排序,如果数据没有indexed,则stored应是true。
stored: 缺省true。说明这个字段被包含在搜索结果中是合适的。如果数据没有stored,则indexed应是true。
sortMissingLast: 指没有该指定字段数据的document排在有该指定字段数据的document的后面
sortMissingFirst: 指没有该指定字段数据的document排在有该指定字段数据的document的前面
omitNorms: 字段的长度不影响得分和在索引时不做boost时,设置它为true。一般文本字段不设置为true。
termVectors: 如果字段被用来做more like this 和highlight的特性时应设置为true。
compressed: 字段是压缩的。这可能导致索引和搜索变慢,但会减少存储空间,只有StrField和TextField是可以压缩,这通常适合字段的长度超过200个字符。
multiValued: 字段多于一个值的时候,可设置为true。
positionIncrementGap: 和multiValued一起使用,设置多个值之间的虚拟空白的数量
StrField类型不被分析,而是被逐字地索引/存储。
StrField和TextField都有一个可选的属性“compressThreshold”,保证压缩到不小于一个大小(单位:char)
< fieldType name =" text " class =" solr.TextField " positionIncrementGap =" 100 " >
solr.TextField 允许用户通过分析器来定制索引和查询,分析器包括 一个分词器(tokenizer)和多个过滤器(filter)
< tokenizer class =" solr.WhitespaceTokenizerFactory " />
空格分词,精确匹配。
< filter class =" solr.WordDelimiterFilterFactory " generateWordParts =" 1 " generateNumberParts =" 1 "catenateWords =" 1 " catenateNumbers =" 1 " catenateAll =" 0 " splitOnCaseChange =" 1 " />
在分词和匹配时,考虑 "-"连字符,字母数字的界限,非字母数字字符,这样 "wifi"或"wi fi"都能匹配"Wi-Fi"。
< filter class =" solr.SynonymFilterFactory " synonyms =" synonyms.txt " ignoreCase =" true " expand ="true " />
同义词
< filter class =" solr.StopFilterFactory " ignoreCase =" true " words =" stopwords.txt "enablePositionIncrements =" true " />
在禁用字(stopword)删除后,在短语间增加间隔
stopword:即在建立索引过程中(建立索引和搜索)被忽略的词,比如is this等常用词。在conf/stopwords.txt维护。
4、fields
< field name =" id " type =" string " indexed =" true " stored =" true " required =" true " />
< field name =" text " type =" text " indexed =" true " stored =" false " multiValued =" true " />
包罗万象(有点夸张)的field,包含所有可搜索的text fields,通过copyField实现。
< copyField source =" cat " dest =" text " />
在添加索引时,将所有被拷贝field(如cat)中的数据拷贝到text field中
作用:
< dynamicField name =" *_i " type =" int " indexed =" true " stored =" true " />
如果一个field的名字没有匹配到,那么就会用动态field试图匹配定义的各种模式。
< dynamicField name =" * " type =" ignored " multiValued=" true " />
如果通过上面的匹配都没找到,可以定义这个,然后定义个type,当String处理。(一般不会发生)
但若不定义,找不到匹配会报错。
5、其他一些标签
< uniqueKey > id </ uniqueKey >
文档的唯一标识, 必须填写这个field(除非该field被标记required="false"),否则solr建立索引报错。
< defaultSearchField > text </ defaultSearchField >
如果搜索参数中没有指定具体的field,那么这是默认的域。
< solrQueryParser defaultOperator =" OR " />
配置搜索参数短语间的逻辑,可以是"AND|OR"。
二、solrconfig.xml
1、索引配置
mainIndex 标记段定义了控制Solr索引处理的一些因素.
useCompoundFile:通过将很多 Lucene 内部文件整合到单一一个文件来减少使用中的文件的数量。这可有助于减少 Solr 使用的文件句柄数目,代价是降低了性能。除非是应用程序用完了文件句柄,否则 false
的默认值应该就已经足够。
2、查询处理配置
query标记段中以下一些与缓存无关的特性:
query部分负责定义与在Solr中发生的时间相关的几个选项:
概念:Solr(实际上是Lucene)使用称为Searcher的Java类来处理Query实例。Searcher将索引内容相关的数据加载到 内存中。根据索引、CPU已经可用内存的大小,这个过程可能需要较长的一段时间。要改进这一设计和显著提高性能,Solr引入了一张“温暖”策略,即把这 些新的Searcher联机以便为现场用户提供查询服务之前,先对它们进行“热身”。
query中的智能缓存:
其中filterCache、queryResultCache、Named caches(如果实现了org.apache.solr.search.CacheRegenerator)可以自热。
每个缓存声明都接受最多四个属性:
对于所有缓存模式而言,在设置缓存参数时,都有必要在内存、cpu和磁盘访问之间进行均衡。统计信息管理页(管理员界面的Statistics)对 于分析缓存的 hit-to-miss 比例以及微调缓存大小的统计数据都非常有用。而且,并非所有应用程序都会从缓存受益。实际上,一些应用程序反而会由于需要将某个永远也用不到的条目存储在 缓存中这一额外步骤而受到影响。