Solr入门指南

Solr是一款独立的企业级搜索服务器,本指南将从Solr的安装、数据导入、查询入手,了解Solr中常见的概念。

Solr的应用场景由最初的内容搜索,现今已延伸到电商产品查询、历史数据查询、地理空间搜索等各类应用场景中。海量数据时代的到来,很多基于关系型数据库的查询业务尽显疲态,Solr迎刃而上逐渐开始大放异彩。

Solr具有类似REST风格的API。可以通过JSON、XML、CSV或通过HTTP上传的二进制文件,将文档放入Solr(称为“索引”)。可以通过HTTP GET请求查询它,并以JSON、XML、CSV或二进制的方式返回结果。Solr基于Lucene,并对Lucene进行了扩展。

Solr安装与启动

下载Solr,解压并运行:

--shell-*cd solr-x.x.x/bin

solr start -e cloud

以SolrCloud模式启动Solr,会询问启用多少个节点,默认2个,直接输入enter(回车)即可,然后会询问端口号,默认8983|7574(因为启用了两个节点),如果被占用可以调整,否则直接回车即可。接着会提示创建用于索引数据的集合:

Now let's create a new collection for indexing documents in your 2-node cluster.
Please provide a name for your new collection: [gettingstarted]


可以输入一个字符串做为名称,如:techproducts(因为后面做查询时会用到这个名字,所以要记住)。然后一路的回车,直到看见:

SolrCloud example running, please visit: http://localhost:8983/solr

至此Solr就启动成功了。

Solr添加索引数据

先创建一个集合:

bin/solr create -c <yourCollection> -s 2 -rf 2

如:

bin/solr create -c films -s 2 -rf 2

此命令使用了默认的configSet(_default),这个configSet附带了两个默认的选项:托管模式和字段猜测。

托管模式(Managed Schema)

这种模式下可以使用Solr的Schema API对Schema进行修改(Schema存储了有关字段和字段类型的详细信息)。

字段猜测(Schemaless Mode)

字段猜测无需在索引之前定义文档(document)的所有字段,因此,可以快速启动Solr,并在有文档(document)时创建字段。

这个功能听起来很棒,实际上Solr不推荐用于生产环境,这种暴力的方式,一旦猜错了,对于拥有数百万个文档的数据集,重建索引是一个糟糕的过程,更可怕的是如果此时已经没有了原数据,重建就无从说起了。
因此,无模式功能(Schemaless Mode)对学习Solr是一个很好的开始,但不要对它有太多的期望。

更多Solr脚本参见Solr控制脚本说明

Solr创建字段

在Solr示例数据中有一个films目录(solr\example\films),其中一个.csv的文件中包含了很多关于电影的信息。这个文件的第一行中包含一部名为.45的电影,如果使用Solr的数据猜测功能,它将被认为是浮点类型的字段,那么会导致后面的数据创建索引失败,所以,需要在创建索引之前,在Solr中设置“name”字段。

curl -X POST -H 'Content-type:application/json' --data-binary '{"add-field": {"name":"name", "type":"text_general", "multiValued":false, "stored":true}}' http://localhost:8983/solr/films/schema

如果Windows系统,可以借助postman之类的工具发送http请求。也可以通过Solr的管理界面创建字段,但它降低了对字段属性的控制粒度。

solr add field

注意:路径中的films参数,与实际的Solr集合名称对应。

Solr复制字段catchall

在开始创建索引之前还需要做一个更改。因为,我们希望查询时不用指定字段,而是全字段匹配,所以,需要将字段复制到一个text字段中,并且在没有指定字段时,该字段是默认的查询字段。如下定义一个复制字段(catchall):

curl -X POST -H 'Content-type:application/json' --data-binary '{"add-copy-field" : {"source":"*","dest":"_text_"}}' http://localhost:8983/solr/films/schema

在管理界面中,选择[添加复制字段],然后填写字段的来源和目标,如下图所示:

solr add copy field

这样就能把所有字段数据复制到“_text_”字段中。

Solr添加索引数据

我们将位于example/films目录下的电影数据添加到索引。它有三种格式:JSON,XML和CSV。选择其中一种格式,并将其索引到“films”集合中:

Linux/Mac

JSON格式

bin/post -c films example/films/films.json

XML格式

bin/post -c films example/films/films.xml

CSV格式

bin/post -c films example/films/films.csv -params "f.genre.split=true&f.directed_by.split=true&f.genre.separator=|&f.directed_by.separator=|"

Windows

JSON格式

C:\solr> java -jar -Dc=films -Dauto example\exampledocs\post.jar example\films\*.json

XML格式

C:\solr> java -jar -Dc=films -Dauto example\exampledocs\post.jar example\films\*.xml

CSV格式

C:\solr-7.7.0> java -jar -Dc=films -Dparams=f.genre.split=true&f.directed_by.split=true&f.genre.separator=|&f.directed_by.separator=| -Dauto example\exampledocs\post.jar example\films\*.csv

CSV命令所包含的额外的参数,是为了确保“genre”和“directed_by”列中由(|)字符分隔的多个条目,能够被Solr正确索引。

注意:-Dc参数与实际的Solr集合名称对应。

Solr查看索引数据

http://localhost:8983/solr/#/<yourCollection> /query
如:
http://localhost:8983/solr/#/films/query

如果在构建数据集合时,使用了其他的名称,访问路径中的名称就需要做相应的调整。

直接点击[Execute Query]按钮,查询数据。

在q标签下方的输入框中填入:.45,(替换掉默认的*:*),可以看出查询结果有了变化。然后再尝试输入directed_by:Gary Lennon。

如果希望通过短语搜索,就需用到双引号,如:q="multiple terms here"

更多查询方法参见Solr示例数据

Solr添加索引工具

bin/post

Solr提供的命令行工具。

./bin/post -c localDocs ~/Documents

DataImportHandler

DataImportHandler(DIH)工具,可以连接到数据库(需要jdbc驱动),邮件服务器或其他结构化数据源。

https://lucene.apache.org/solr/guide/7_7/uploading-structured-data-store-data-with-the-data-import-handler.html#uploading-structured-data-store-data-with-the-data-import-handler

SolrJ

SolrJ是一款基于Java的Solr客户端,用于与Solr交互。SolrJ用于基于JVM的语言,以编程方式创建要发送给Solr的文档。

Documents Screen

使用Admin UI Documents选项卡(位于http://localhost:8983/solr/#/localDocs/documents)粘贴要添加索引的文档。或者从文档类型下拉列表中选择document Builder,一次构建一个文档。单击表单下面的Submit Document按钮来索引文档。

Solr 数据处理

Solr的数据模式可以在有与无之间自由切换。Solr Schemaless模式(模式猜测)便于入门,配置模式则可用于构建稳定的生产环境。动态字段的特性方便动态添加新字段,Solr能够通过外部配置文件,声明禁用词列表,同义词列表和受保护词列表。并通过扩展的方式,来支持应用专有格式和原本不支持的数据类型。

Solr document

文档是Solr最基本的信息单元,它是一组描述内容的数据。如,关于食谱的document会包含成分、说明、烹饪时长,所需工具等。关于人的document可能会包含该姓名、传记,喜欢的颜色和鞋码。关于书籍的文档可以包含标题、作者、出版年份、页数等。

在Solr中document由字段组成,字段拥有更具体的信息,如:名字和姓氏、鞋子大小。字段可以包含不同类型的数据,如,文本、浮点数。字段类型告诉Solr如何解析字段以及如何查询字段,正确定义字段类型,有助于用户在执行查询时得到更好的结果。

添加文档时,Solr会获取文档字段中的信息,并将该信息添加到索引中。执行查询时,Solr通过查询索引返回匹配的文档。

Solr Schema File

Solr schema用于告诉Solr,如何对document进行索引构建。Solr Schema文件中存储着字段类型和字段定义信息。这个文件的名称和位置与Solr的配置有关。managed-schema是它的名称。可以通过solrconfig.xml文件中的<schemaFactory/>节点进行修改:

Solr Schema分为托管模式(Managed Schema)和经典配置(schema.xml)两种,Solr 6.0之后默认使用托管模式,这种模式下支持Schema API处理Schema数据,灵活性更高。

Managed Schema:

--markup-*<schemaFactory class="ManagedIndexSchemaFactory">
    <bool name="mutable">true</bool>
    <str name="managedSchemaResourceName">managed-schema</str>
  </schemaFactory>

Classic schema.xml:

<schemaFactory class="ClassicIndexSchemaFactory"/>

如需修改Schema文件的默认名称,通过显式配置ManagedIndexSchemaFactory,把mutable选项设为true(false用于“锁定”修改)。managedSchemaResourceName是可选参数,为Schema文件名称,默认为“managed-schema”。该值可以是“schema.xml”以外的任何名称。

schema.xml是Schema文件的传统名称。如果使用的是SolrCloud,在本地文件系统中则可能找不到这类文件。
两种模式之间的切换,参见solr classic schema

有关修改Solr Schema定义可以参见schema factory definition in solrconfig

Schemaless Mode

Schemaless Mode是一组Solr功能,当它们一起使用时,允许用户通过简单地索引样本数据,来快速构建有效的schema,而无需手动编辑schema。

使用Solr的Schemaless Mode需要具备三个条件:托管模式(Managed schema)、字段猜测(Field value class guessing)、(自动添加字段)Automatic schema field addition, based on field value class。

使用Schemaless Mode三个选项的设置参见:solr using the schemaless example

Solr定义字段类型

当通过字段对应的索引查询文档时,Solr会分析字段的类型。字段类型在schema.xml中定义,通过fieldType元素定义具体类型。Solr内置了很多可用的字段类型。提供了货币日期枚举的处理,以及外部文件处理方式(Solr ExternalFileField Type),Solr ExternalFileField Type常用于临时提高某些document的排名。

<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" />
    <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>

上面示例中的第一行包含了名称为text_general,类型为solr.TextField的字段。其余部分是关于字段分析时(Field Analysis)所要用到的。在schema.xml文件中,solr.是org.apache.solr.schema.或org.apache.solr.analysis.的缩写。所以,solr.TextField代表了org.apache.solr.schema.TextField类,字段的实现类(solr.TextField)负责确保字段被正确处理。具体细节参见Solr field type definitions and properties

Solr 定义字段

Solr中的字段通过schema.xml文件中的field元素定义,在前面已经了解如何定义字段类型,所以,定义字段就相对简单很多了。

<field name="price" type="float" default="0.0" indexed="true" stored="true"/>

示例中定义了一个名为price的字段,其类型为float,默认值为0.0。索引和存储属性被显式地设置为true,针对float类型所做的属性设置都将被继承到此。

field属性说明

name

字段的名称,每个字段都必须有一个名称。字段名称应仅包含字母数字或下划线字符,不能以数字开头。目前尚未严格执行此操作,但无法保证后向兼容性。包含前导和尾部下划线的名称(如,_version_)目前是保留的。 

type

字段的类型,其值来源于fieldType定义。每个字段必须有一个type。

default

默认值,在索引时如果文档的此字段中没有值则使用默认值。

更多其他属性参见Solr optional field type override properties

Solr Copying Fields

如果希望Sorl以多种方式解释某些文档的字段。可以使用Solr的Copying Fields,这种复制字段机制,还可以将几种不同的字段类型作为一个输入。

<copyField source="cat" dest="text" maxChars="30000" />

示例中,Solr将cat字段复制到名为text的字段中。这意味着两个具有相同内容的字段,可以使用不同的分析链以不同的方式存储在索引中。

此功能的一个常见用法是创建单个“搜索”字段,当用户或客户端未指定要查询的字段时,使用该字段作为默认查询字段。

<copyField source="*_t" dest="text" maxChars="25000" />

例如title,author,keywords,和body都应该是默认搜索字段,可以把这些字段都复制到一个catchall的字段中,把catchall作为默认查询字段。需要注意的是复制发生在source级别,不能把一个副本作为另一个副本的源,以下是错误的示范:

<copyField source="here" dest="there"/>
<copyField source="there" dest="elsewhere"/>

更多细节参见:Solr copying fields

Solr动态字段(Dynamic Fields)

Solr动态字段允许Solr在索引时使用没有明确定义的字段。如果忘记定义字段,Solr的这一特性提供了一定的灵活性,以保证应用程序不那么脆弱。

动态字段和常规字段一样,除了名称中带有通配符。在Solr索引文档时,当一个字段没匹配到显式定义的字段,都可以与动态字段尝试匹配。

<dynamicField name="*_i" type="int" indexed="true"  stored="true"/>

例如,schema中包含名称为*_i的动态字段。如果尝试使用cost_i字段索引文档,但cost_i未在schema中显式定义,则cost_i字段将与*_i进行匹配。

Solr Schema API

Schema API是一种通过HTTP REST接口管理schema 元素的方式。API提供对Solr Schema读写访问权限。支持进行字段和字段类型进行添加、删除、替换等操作。

--shell--curl -X POST -H 'Content-type:application/json' --data-binary '{
  "add-field":{
     "name":"sell_by",
     "type":"pdate",
     "stored":true }
}' http://localhost:8983/api/cores/gettingstarted/schema

更详细示例参见:Solr schema api

Solr属性分析(Field Analysis)

Field analysis是告诉Solr如何对传入的数据进行索引的构建,这个过程的更准确的叫法可能是处理(processing)或者消化(digestion),但Solr官方称之为分析(analysis)。

一个关于人的文档中,其中一个字段用于存放人物的传记,传记中的每个词都必须编入索引,以便能够通过查询传记中的相关信息快速找到此人。然而,传记中可能包含许多平时生活中不会关心的词,如“the”,“a”,“to”等等。又或者希望查询时大小写不敏感。这些问题的解决方案都需要依赖Field Analysis。

Solr在处理文本数据时,涉及到三个主要概念:分析器、标记器和过滤器。

字段分析器(Field analyzers )

字段分析器(Field analyzers )在文档被索引和查询时使用,分析器检查字段的文本并生成令牌流。分析器可以是单个类,也可以由一系列标记器和过滤器类组成。

分析器通过schema.xml文件中<fieldType>子元素配置。在正常使用中,只有类型为“solr.TextField或solr.SortableTextField的字段才指定分析器。配置分析器最简单的方法是使用一个analyzer元素,该元素的class属性是一个完全限定的Java类。此类必须是org.apache.lucene.analysis.Analyzer子类。例如:

<fieldType name="nametext" class="solr.TextField">
  <analyzer class="org.apache.lucene.analysis.core.WhitespaceAnalyzer"/>
</fieldType>

注意:此处的solr.是org.apache.solr.的缩写。

即使是最复杂的analysis需求,通常也可以被分解为一系列离散的、相对简单的处理步骤。Solr发行版附带了大量的标记器和过滤器,它们涵盖了大多数可能遇到的场景。建立分析仪链非常简单,指定一个<analyzer>元素(没有class属性),其子元素按照希望的顺序安排分词器和过滤器工厂。

<fieldType name="nametext" class="solr.TextField">
  <analyzer>
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.StopFilterFactory"/>
    <filter class="solr.EnglishPorterFilterFactory"/>
  </analyzer>
</fieldType>

更多细节参见solr analyzers

分词器(Tokenizers)

分词器(Tokenizers)将字段数据分解为词法单元或令牌。

<fieldType name="text" class="solr.TextField">
  <analyzer>
    <tokenizer class="solr.StandardTokenizerFactory"/>
  </analyzer>
</fieldType>

tokenizer元素中指定的类不是实际的tokenizer,而是实现TokenizerFactory的类。通过调用工厂类,根据需要创建tokenizer实例。工厂创建的对象必须是Tokenizer的子类。
更多细节参见solr tokenizers

过滤器(Filters)检查令牌流以决定是否保留、转换、丢弃,或创建新的令牌。标记器和过滤器可以组合成管道或链,前一个的输出作为下一个的输入。这样的标记器和过滤器序列称为分析器,分析器的输出结果用于匹配查询结果或构建索引。

<fieldType name="text" class="solr.TextField">
  <analyzer>
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.EnglishPorterFilterFactory"/>
  </analyzer>
</fieldType>


更多细节参见solr filters

Solr索引(Solr Indexing)

Solr索引可以接受来自不同来源的数据,包括XML、CSV,数据库以及常用的文件格式(如Microsoft Word或PDF)。

Solr添加索引的三种最常用方法:Solr Cell框架提取文件、HTTP请求上传XML文件、Solr Java API提取数据。无论使用哪种数据提取方式,都会有一个通用的基础数据结构,用于将数据输入Solr索引:包含多个字段的文档(document),每个字段都有名称和内容,这些字段可能是空的。通常有一个惟一ID字段(类似于数据库中的主键),尽管Solr并不严格要求使用惟一ID字段。

Solr Cell

Apache Tika是一款内容检测、分析的工具包,可从上千种不同的文件类型(如PPT,XLS和PDF)中检测提取元数据和文本。Solr利用Tika项目构建了一个框架(Solr Cell),用于将许多不同文件格式的解析器(如Apache PDFBoxApache POI)集成到Solr中。

Solr Cell默认不包含在Solr中,所以需要进行配置。但如果使用了Solr的示例配置项,它默认是配置了Solr Cell的。Solr附带了两个示例配置集(server/solr/configsets),配置集的名称为_default和sample_techproducts_configs。

如果对这些配置没什么兴趣,可以尝试Solr schemaless模式,它包含了Tika框架示例配置集。

--shell-*bin/solr -e techproducts

启动Solr后,可以发送HTTP POST发送,操作Solr附带的示例PDF文件:

curl 'http://localhost:8983/solr/techproducts/update/extract?literal.id=doc1&commit=true' -F "myfile=@example/exampledocs/solr-word.pdf"

说明:通过URL调用了ExtractingRequestHandler,上传了一个solr-word.pdf文件,并为其分配一个唯一ID:doc1。

使用commit=true要求SOLR执行索引文件提交后,能够立即搜索到。如果批量加载很多文档,为获取最佳性能,在完成之前不要调用commit命令。

-F标志是curl POST请求上传上载二进制文件(multipart/form-data)时的参数项。该@符号标示上传附件。

参数myfile=@example/exampledocs/solr-word.pdf为上传文件。

手动配置Solr Cell

如果没有使用示例配置集,则需要手动配置以加载Solr Cell所需的jar包。通过在solrconfig.xml中查找ExtractingRequestHandler及其依赖项:

--markup-*<lib dir="${solr.install.dir:../../..}/contrib/extraction/lib" regex=".*\.jar" />
<lib dir="${solr.install.dir:../../..}/dist/" regex="solr-cell-\d.*\.jar" />

然后,在solrconfig.xml中配置ExtractingRequestHandler。下面是在Solr的_default configset中找到的默认配置,可以根据需要修改:

<requestHandler name="/update/extract"
                startup="lazy"
                class="solr.extraction.ExtractingRequestHandler" >
  <lst name="defaults">
    <str name="lowernames">true</str>
    <str name="fmap.content">_text_</str>
  </lst>
</requestHandler>

在使用Solr Cell框架时,请记住以下几点:

Tika将自动尝试判断文档类型(如:Word、PDF、HTML)并提取内容。可以使用stream.type参数为Tika显式指定MIME类型。有关支持的文件类型,参见Tika formats

Tika的内部工作原理简单地说就是,把已解析文档的内容合成XHTML文档,并传递给Solr Cell的SAX ContentHandler。Solr响应Tika的SAX事件,从提取的内容中创建一个或多个文本字段。

Tika根据DublinCore(元数据规范)等规范生成标题,主题和作者等元数据。可用的元数据高度依赖于文件类型及所包含的内容。

Solr Cell将内部XHTML中的文本连接到内容字段。还可以配置哪些元素应该被包含哪些应该被忽略,以及哪些元素应该映射到另一个字段。

Solr Cell默认将每个元数据块映射到同名字段,如果愿意也可以通过参数控制修改这一点。

当Solr Cell在内部完成SolrInputDocument创建后,Solr索引创建程序将接管。

关于更多细节配置参见Solr Cell configuring