Solr 4.10 手册

本文档参考自 apache-solr-ref-guide-4.10.pdf
测试环境使用 Solr 为 CDH 最新发行版本:solr-4.10.3-cdh5.5.1 (官方 4.10.3 发布于2014-12-29)
当前 Solr 官方最新版为:5.5.1 (截至到2016-06-18)

开始

安装

下载:https://archive.cloudera.com/cdh5/cdh/5/solr-4.10.3-cdh5.5.1.tar.gz

Solr 4 可以作为 Java servlet 运行在Tomcat Jetty或Resin中,Solr发行版中包含了一个运行在Jetty的Example范例,你可以使用这个Example作为模板部署你的实例,推荐使用搭载了Jetty Server的Solr,因为它做了一些性能优化。

备注:从Solr 5.0开始,Solr已经是个独立的服务。

JDK 环境

1.7+

运行

Solr 解压后可直接运行,bin/solr脚本默认会将主目录定位到example目录,运行后会包含一个 collection1 的 Core,以下为主要指令说明:

# 查看帮助
bin/solr --help
选项 说明 示例
start 启动 bin/solr start
stop 停止 -all 参数 bin/solr stop
-f 前台运行,使用-e运行范例时无效 bin/solr -f
-h hostname 默认为localhost bin/solr start -h search.solr.com
-p 监听端口,默认为8983 bin/solr start -p8989
-m 指定JVM -Xms -Xmx的 最大堆栈内存 bin/solr start -m 2g
-d 定义Solr server 路径,默认为example/ bin/solr start -d [serverdir]
-s 定义Solr home 路径,默认为example/solr bin/solr start -s [homedir]
-e 运行内置 example bin/solr start -e dih
-cloud -c 启动SolrCloud模式,默认会启动一个内置的Zookeeper,如果是外部的Zookeeper,需要指定-z参数
-z Zookeeper列表 bin/solr start -c -z server1:2181,server2:2181
-a 额外的 JVM 信息 bin/solr start -a "-Xdebug -Dxx=yy"
-V 启动调试信息 bin/solr -V

运行成功可通过地址访问管理界面:

http://localhost:8983/solr/

备注:通过查看文档,新版本 Solr 5 指令略有不同,增加了更多的工具,比如status, create 等,并且范例也多了一些。

运行机制

Solr 4 实际上内置了一个Jetty Server,通过bin/solr启动内置的Jetty,当然你也可以使用外部的 Jetty来运行。

如果你需要-d运行一个独立的Solr实例,你可以复制example作为模板,以下是目录结构:

├── contexts   # Jetty配置
├── etc  # Jetty配置
├── lib  # 库
├── logs  # 日志
├── resources  # 配置文件
├── scripts # 存放一些脚本,比如SolrCloud的脚本
├── solr  # Solr 的默认home目录,存放core等配置
├── start.jar  # jetty启动jar
└── webapps  # 包含solr.war的目录

接下来就可以通过自带的脚本启动新的Solr实例了

bin/solr -d /usr/local/server/solr/home/

增加测试文档

启动Solr后,可以添加一些测试文档

Solr 自带了一些测试文档,和一个工具post.jar,这些在目录 example/exampledocs/ 下,查看帮助:

java -jar post.jar -help
java -jar post.jar *.xml
java -Durl=http://localhost:8983/solr/collection1/update -jar post.jar *.xml

备注:使用post.jar添加文档我没有测试成功,可能是由于缺少jar包或者mac环境的原因,不过可以使用目录下自带的post.sh脚本来提交文档。

./post.sh *.xml

查询测试文档

通过上面的步骤,现在我们可以尝试进行一些查询,通过构造查询字符串,比如,

# 在所有的文档字段中查找video关键字
http://localhost:8983/solr/select?q=video

# 在name字段中,查找black关键字:
http://localhost:8983/solr/select?q=name:black

# 搜索价格区间,并按照类别分组,返回指定字段
http://localhost:8983/solr/select?q=price:[0%20TO%20400]&fl=id,name,price&facet=true&facet.field=cat

概览

Solr 基于 Apache Lucene 项目,是一个高性能、分布式、全文检索引擎。

复制
当查询量过大时,可通过复制功能,master->slave(1,2,3),简单轮询,缓冲查询负载

分片
当文档数量过大,索引过大,超出单机限制时,可以将索引分片。这时候查询会分布到多个分片服务器上,查询时合并返回结果。(shard1,shard2)

复制+分片
当文档数和查询都巨大时,可能需要联合使用复制和分片功能,Solr提供SolrCloud 架构。

(
shard1(master->slave(1,2,3))
shard2(master->slave(1,2,3))
shard3(master->slave(1,2,3))
)

更进一步

当 solr 运行在应用服务器中,需要一个主配置目录权限,主配置目录会包含一些重要的配置信息,以及索引数据。

一个典型的目录结构:

<solr-home-dir>
  solr.xml
  core1/
    conf/
       solrconfig.xml
       schema.xml
    data/
  core1/
    conf/
       solrconfig.xml
       schema.xml
    data/

solr.xml
主配置,指定了solr core的配置信息,如配置Solr支持多个cores

solrconfig.xml
针对core的配置,控制一些高级特性,比如指定索引数据保存的路径等

schema.xml
针对core的配置,描述了solr应该怎样去索引文档,可以定义一个文档的集合字段,字段类型,具有非常丰富和强大的配置选项。

SolrCloud 模式下会将core的conf/配置信息通过Zookeeper进行管理

Solr 管理用户接口 Web GUI

Dashborad 仪表板
Logging 日志以及日志级别
Cloud Screens SolrCloud 模式下运行时显示有关节点的信息。
Core Admin 核心的管理信息。
Java Properties Java属性。
Thread Dump 每个线程的详细信息与状态信息。
Core-Specific Tools 核心工具

  • Analysis 分析特定字段中的数据。
  • Dataimport 有关数据导入处理程序的当前状态信息。
  • Documents 提供允许您直接从浏览器中执行各种Solr的索引的命令。
  • Files 显示当前的核心配置文件solrconfig.xml中和schema.xml
  • ping
  • Plugins/Stats 插件/统计,显示统计插件和其它安装的组件。
  • Query 提交关于核心的各种元素的结构化查询。
  • Replication -显示你的核心目前的副本状态,并让您启用/禁用副本。
  • Schema Browser 显示模式的结构。

查询窗口

选项 说明
Request-Handler 指定请求查询处理类型
q 主查询
fq 过滤器,对主查询结果进行过滤,不影响评分
sort 排序,创建索引非多值属性都可以作为排序字段,还可以通过文档评分 score 进行排序
start,rows 开始,偏移量
fl 字段列表,通过alias:field实现别名
wt 返回格式
indent 缩进换行,是否可读
debugQuery 调试信息
dismax dismax 查询分析器
edismax 扩展查询分析器
hl 高亮
facet 分类或维度
spatial 数据的空间或地理空间搜索
spellcheck 拼写检查

文档、字段、模式设计

概述

Solr的基础原理很简单,你将一些数据信息提交给它,然后向它提出问题,找到你想要找到的信息,你将信息提交给Solr的过程称之为建索引(indexing)或数据更新(updating),当你提交问题,称之为查询(query)。

Schema是定义Solr如何将输入的文档建立索引的。

Solr是怎样理解这个世界的

Solr的基本单元是文档(document),文档是描述信息的一组数据。一个食谱文档可能会包含原材料、操作教程、准备的时间、制作的时间、需要的工具等等。描述一个人的文档可能包含名字、个人简介、喜欢的颜色、鞋子的大小。描述一本书的文档可能包含书名、作者、出版时间、页数等。

在Solr看来,文档是由字段(field)组成的,代表更具体的某类信息。鞋码可以是一个字段,姓和名都可以是一个字段。

字段可以包含各种类型的数据,比如一个名字字段是文本类型的,鞋码应该是浮点型的,这样就可以是6或9.5的。很显然字段的定义是很灵活的,你也可以将鞋码定义成文本类型,只有当你正确的定义了字段,Solr才能正确的解析这些内容,你的用户才能获得更好的查询结果。

在Solr中通过定义字段的类型来表示该字段是什么类型的数据,如何解析这个字段,以及如何处理对这个字段的查询。

当你向Solr中添加一个文档,Solr会将文档解析成各个字段然后添加到索引中,当发起查询时,Solr会快速的查找索引并返回匹配的文档结果。

字段解析

字段解析是告诉Solr对提交的数据如何建立索引,一个更确切的描述这一过程的词可以是processing或digestion,但官方的名称是analysis.

比如一个描述人的文档中的个人简介的字段,这个字段的每个文字都需要建立索引,这样你才能快速找到哪个人和数学或计算机有关。

然而个人简介可能包含很多文字,像“的”、“吗”、“啊”这类词可能并不需要关注。另外英文中经常有首字母大写的单词,比如包含“Ketchup”,而用户需要查询“ketchup”,你当然需要Solr也能查找到包含大写字母的文档。

上面提到的这些都是字段解析。对于个人简介字段,你需要告诉Solr如何将文本内容进行分词,比如需要告诉Solr将所有词处理成小写,并移除停用词。

字段解析是字段类型的很重要的部分。

Solr 字段类型

字段类型的定义

包含以下四点:

字段类型的名称(必须有)
实现类名(必须有)
如果字段类型是TextField,需要包含该字段类型的分词器
字段类型属性-取决于实现类,某些属性是你必须的

字段类型是在schema.xml中的types标签中定义的。每个字段类型定义在fieldType标签中,以下是text_general类型的定义:

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

示例中的第一行包含类型的名称 text_general 和实现类名 solr.TextField 。其他部分是对字段解析的定义。

实现类来保证字段会被正确的处理,schema.xml中类名,solr是org.apapche.solr.schema或者org.apache.solr.analysis的缩写。因此,solr.TextField实际是org.apache.solr.schema.TextField类。

字段类型属性 实现类定义了该类型的大部分实现行为,另外可以定义可选属性。如以下示例中定义了另外两个属性sortMissingLast和omitNorms:

<fieldType name="date" class="solr.TrieDateField" sortMissingLast="true" omitNorms="true"/>

字段类型的属性

主要包含以下三类:

  • 类型实现类的属性
  • 通用属性
  • 可覆盖的默认属性

通用属性:

属性 说明
name 字段类型的名称,建议名称仅包含字母数字和下划线,不以数字开头,虽然目前并没有严格限制
class 该类型用于存储和索引字段数据的类名,可以使用“solr.”来简写类名,如果使用第三方类则需要写全类名。“solr.TextField”的完整类名是“org.apache.solr.schema.TextField”.
positionIncrementGap  用于多值类型的字段,指定各值之间的距离,防止出现假词组匹配出现
autoGeneratePhraseQueries  用于文本类型字段,如果为true,Solr自动将临近的词作为词组查询,如果为false,则词组必须用双引号引起来才被认为是词组
docValuesFormat 自定义DocValuesFormat,需要在solrconfig.xml中定义SchemaCodecFactory
postingsFormat 自定义PostingFormat,需要在solrconfig.xml中定义SchemaCodecFactory

可覆盖的默认属性:

属性 说明 可选 默认
indexed 如果为true,字段的值可以用于查询 true/false true
stored 如果为true,字段的值可以在查询结果中返回 true/false true
docValues 如果为true,字段的值会被放到一个基于列的结构中 true/false false
sortMissingFirst, sortMissingLast 当没有指定排序字段时,文档的排序方式。在Solr3.5以后,只对数值类型、Trie和日期类型有效 true/false false
multiValued 如果为true,表示该类型的字段在一个文档中可以包含多个值 true/false false
omitNorms 如果为true,会忽略该字段的norm计算(禁用基于文档长度的计算和该字段索引时的评分计算,节省内存)。默认对所有原始类型(非分词的字段类型)为true,如int, float, data, bool, string.只有全文本字段或者需要在建索引时计算评分时才需要norms true/false *
omitTermFreqAndPositions 如果为true,忽略词频、位置信息,禁用会对性能有一定提升,而且会减少索引的存储空间。当基于位置的查询应用到该属性为true的字段时会查不到文档。该属性对非文本类型字段默认为true。 true/false *
omitPositions 和omitTermFreqAndPositions类似,但保留了词频信息 true/false *
termVectors,termPositions,termOffsets 这些选项决定Solr是否保存每个文档的词向量(term vector),可以选择性的包含位置信息、每个词在向量中的偏移距离。可以加快高亮和其他辅助功能的执行速度,但会比较大的影响索引文件的大小。一般情况下这些信息并不是必要的。 true/false false
required 表明该字段是必须字段,如果提交的文档中该类型字段缺少,则Solr会拒绝添加文档。该属性默认是false true/false false

Solr 内置的字段类型

属性 说明
BinaryField 存储二进制数据
BoolField 保存true或false。以“1”、“t”或“T”开头的值都被转换为true,其他值则为false
CollationField 支持基于Unicode的排序规则和范围查询。如果你可以使用ICU4J,ICUCollationField会是一个更好的选择。
CurrencyField 支持货币和汇率。
ExternalFileField 从磁盘上的文件中获取值。
EnumField 可以定义一组枚举值,但枚举值按字母顺序或数值顺序排序往往不合理,(例如枚举值是损伤程度).该类型会附带一个配置文件,列出枚举值的顺序。
ICUCollationField 支持基于Unicode的排序规则和范围查询。
LatLonType 地理位置搜索:一组经度和维度值(latitude/longitude),该类型是维度值(latitude)。
PointType 地理位置搜索:任意n维的点。可以用来搜索蓝图或CAD图。
RandomSortField 该类型字段并不包含值,以该类型字段排序的查询会以随机形式排序。通过动态字段来使用这个特性。
SpatialRecursivePrefixTreeFieldType 地理位置搜索:接受“维度,经度”格式的字符串或其他熟知类型的值。简称RPT。
StrField String类型(UTF-8编码的字符串或Unicode)
TextField 文本类型,一般包含多个单词
TrieDateField 日期类型,表示精确到毫秒的时间。参见precisionStep="0"可以让日期排序更快索引文件更小;默认precisionStep="8"可以有更好的范围查询效率。
TrieDoubleField Double类型(64位IEEE浮点型)。precisionStep="0"可以让日期排序更快索引文件更小;默认precisionStep="8"可以有更好的范围查询效率。
TrieField 如果使用该类型,需要包含type属性,合法的属性值有integer、long、float、double、date。这种方式和使用对应类型的Trie字段一样。precisionStep="0"可以让日期排序更快索引文件更小;默认precisionStep="8"可以有更好的范围查询效率。
TrieFloatField 浮点型(32位IEEE浮点型)。precisionStep="0"可以让日期排序更快索引文件更小;默认precisionStep="8"可以有更好的范围查询效率。
TrieIntField 整型(32位有符号整型)。precisionStep="0"可以让日期排序更快索引文件更小;默认precisionStep="8"可以有更好的范围查询效率。
TrieLongField 长整形(64位有符号整型)。precisionStep="0"可以让日期排序更快索引文件更小;默认precisionStep="8"可以有更好的范围查询效率。
UUIDField Universally Unique Identifier (UUID).当传入值“NEW”时,Solr会创建一个新的UUID。注意:不建议在使用SolrCloud时创建一个默认值是“NEW”的UUIDField类型的实例,而且UUID不能是unique字段,因为每一份文档的复制都会创建一个UUID值。建议在添加文档的时候使用UUIDUpdateProcessorFactory来生成UUID值。

字段属性客户使用案例

以下是一些客户使用案例总结:

Use Case indexed stored multiValued omitNorms termVectors termPositions docValues
search within field (搜索)   true 
retrieve contents (结果返回) true 
use as unique key (唯一键)  true false
sort on field (排序) true 7 false true 1 true 7
use field boosts 5 false
document boosts affect searches within field false
highlighting (高亮) true 4 true true2  true 3
faceting 5 true7 true7
add multiple values, maintaining order true
field length affects doc score false
MoreLikeThis 5 true 6
  1. 建议但非必需
  2. 如果存在,将被使用。非必需
  3. 如果 termVectors=true
  4. 必需定义这个字段,其实并不需要indexed
  5. 参见:优化、过滤章节
  6. Term vectors are not mandatory here. If not true, then a stored field is analyzed. So term vectors are recommended, but only required if stored=false.
  7. indexed 与 docValues 需要其中一个, 并不需要全部为true. 但 DocValues 会在某些场景拥有特殊效果

字段定义

字段同样定义在 schema.xml 文件, 下面定义了一个名称为price,类型float,默认值为0.0的字段,indexed 与 stored属性被指定,同时会继承所有内置的float类型的其他属性。

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

拷贝字段

Solr 提供了一种手段,你可以拷贝已经定义的字段,应用于新字段上,可以将多个字段拷贝到一个字段上。

<copyField source="title" dest="text" />
<copyField source="content" dest="text" />

动态字段

动态字段允许你不需要明确的在schema.xml声明你的字段,而借助一个表达式来匹配您的字段,当未匹配到任何字段时,才会进行动态字段的匹配。

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

建议您在配置文件中包含所有的基础动态字段,这一般很有用

其他元素

Unique Key

通过uniqueKey来指定你期望唯一键字段,依赖您的应用架构,并不是必需的。

<uniqueKey>id</uniqueKey>

Default Search Field

默认搜索字段,通过 df 参数来指定,默认 df 是 text 字段

Query Parser Default Operator

默认操作符解析,通过q.op 参数指定

Similarity

相似度或者相关度,Solr 搜索时给予文档的评分,通常是为了自定义排序,可以定义一个全局的配置也可以为每个字段定义

DocValues

Solr 4.2 增加了这个特性,DocValues 主要控制 Solr 为了某种目的更好的创建索引。Solr 为了提高检索效率,默认使用倒排索引,在某些情景,如排序、分类维度、高亮,并不能更好的执行。

具体不是很理解,需要深入了解。

索引与基本数据操作

Simple Post Tool

官方提供的简单提交测试数据的工具

Uploading Data with Index Handlers

Solr 提供的默认索引接口

Uploading Structured Data Store Data with the Data Import Handler

Solr 提供了很强大的数据导入工具,DIH,可以从关系数据库、XML等数据源导入数据生成索引。甚至是基于http协议的RSS等。可参考:https://wiki.apache.org/solr/DataImportHandler

需要在 solrconfig.xml 中的 配置段显式的引用 DataImportHandler jars

如果是MySQL数据库,你还需要增加mysql驱动所在的目录,比如mysql-connector-java-5.1.38-bin.jar在contrib/dataimporthandler-extras/lib/目录下:

<lib dir="${solr.install.dir:../../../..}/contrib/dataimporthandler-extras/lib/" regex=".*\.jar" />
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-dataimporthandler-.*\.jar" />

或者全路径:

<lib dir="/opt/cloudera/parcels/CDH/lib/solr/" regex="mysql-connector-java-.*\.jar" />
<lib dir="/opt/cloudera/parcels/CDH/lib/solr/" regex="solr-dataimporthandler-.*\.jar" />

概念

DataSource, 数据源,定义了数据来源,可包括数据库、DSN、HTTP来源
Entity, 实体,概念上一个实体对应了一个文档集合,包含了多个字段,对于RDBMS,一个实体对应了一个视图或表,可能是通过一个或多个SQL语句来生成
Processor,处理器,实体处理器是用来处理、转换数据源的
Transformer, 转换器,每组通过数据源获取的字段即可都可以应用转换,这个过程可以修改字段,创建新字段,或者从单行生成多行,内置了一些转换器,例如可以转换时间格式、去除HTML标记等等。

配置

  • solrconfig.xml

注册DIH接口:

<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
    <lst name="defaults">
      <str name="config">/path/to/data-config.xml</str>
    </lst>
  </requestHandler>

config参数指定了DIH的配置文件,其中定义了包括数据源、如何获取数据、获取什么数据以及处理过程。

  • DIH 配置文件

比较长,省略

  • DIH 命令

abort,取消
delta-import,增量,
full-import,全量,会启动一个新的线程,不会阻塞Solr的查询。
reload-config,重载配置
status,状态

  • Property Writer 属性写入器

可选。为增量查询定义了日期格式、语言等配置

  • DataSource

定义了数据来源和类型,主要包含以下几种,ContentStreamDataSource,FileReaderDataSource,FileDataSource,JdbcDataSource,URLDataSource

<dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/dbname" user="db_username" password="db_password"/>

可以定义多个数据源多个实体:

<dataSource type="JdbcDataSource" name="ds-1" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://db1-host/dbname" user="db_username" password="db_password"/>
<dataSource type="JdbcDataSource" name="ds-2" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://db2-host/dbname" user="db_username" password="db_password"/>

<entity name="one" dataSource="ds-1" ...>
   ..
</entity>
<entity name="two" dataSource="ds-2" ...>
   ..
</entity>
  • EntityProcessors

实体处理器解析、转换数据添加到 Solr 索引中,包括以下属性:

datasource, 数据源名称,如果有多个数据源,必须
name, 必须,实体名称
pk,它和schema.xml中的uniqueKey没有关系。uniqueKey决定了索引的主键标识,主键重复会进行覆盖,而pk只是用来做增量索引时使用。当然,它们可以是同一个值。
Processor,当数据源不是RDBMS时必须
onError,abort|skip|continue
preImportDeleteQuery
postImportDeleteQuery
rootEntity
transformer
cacheImpl
cacheKey
cacheLoopup

  • SQL Entity Processor

query
deltaQuery
parentDeltaQuery
deletedPkQuery
deltaImportQuery

示例(1) 单表

创建测试表item:

CREATE TABLE `item` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL DEFAULT '',
  `created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `isdeleted` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

使用 -e dih 启动Solr后,修改db-data-config.xml,其中字段的映射关系是可以省略的:

<dataConfig>
    <dataSource driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/solr" user="root" password="123123" batchSize="-1" />
    <document>
        <entity name="item" pk="id" query="SELECT * from item WHERE isdeleted = 0 "
                deltaImportQuery="SELECT * FROM item WHERE id = ${dataimporter.delta.id}"
                deltaQuery="SELECT id FROM item WHERE updated > '${dataimporter.last_index_time}' " 
                deletedPkQuery="SELECT id FROM item WHERE isdeleted = 1 AND updated > '${dataimporter.last_index_time}'">
        </entity>
    </document>
</dataConfig>
  1. 增量索引要求,需要增加一个更新时间戳字段:updated,Solr通过这个字段来确定上次索引以后哪些行需要更新
  2. 增量索引如果需要删除索引,需要增加一个标记删除的字段:isdeleted
  3. 物理删除表记录,并不会同步删除索引,不过可以通过触发器,增加一个额外delete表来进行实现,较复杂

可以定义多个实体,每个实体对应一个表,但是要保证主键的唯一性,否则新的数据会覆盖旧的数据,如下所示,item2表中含有相同的主键数据将会覆盖item的索引:

<dataConfig>
    <dataSource driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/solr" user="root" password="123123" batchSize="-1" />
    <document>
        <entity name="item" pk="id" query="select * FROM item WHERE isdeleted = 0 "
                deltaImportQuery="SELECT * FROM item WHERE id = ${dataimporter.delta.id}"
                deltaQuery="SELECT id FROM item WHERE updated > '${dataimporter.last_index_time}' " 
                deletedPkQuery="SELECT id FROM item WHERE isdeleted = 1 AND updated > '${dataimporter.last_index_time}'">
        </entity>
        <entity name="item2" pk="id" query="select * from item2 where isdeleted = 0 "
                deltaImportQuery="SELECT * FROM item2 WHERE id = ${dataimporter.delta.id}"
                deltaQuery="SELECT id FROM item2 WHERE updated > '${dataimporter.last_index_time}' " 
                deletedPkQuery="SELECT id FROM item2 WHERE isdeleted = 1 AND updated > '${dataimporter.last_index_time}'">
        </entity>
    </document>
</dataConfig>

示例(2) 多表

已知有以下DB结构,item与feature是一对多关系,item与category是多对多关系

CREATE TABLE `item` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL DEFAULT '',
  `created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `isdeleted` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `feature` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `item_id` int(11) unsigned NOT NULL,
  `description` varchar(32) NOT NULL DEFAULT '',
  `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `category` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `catname` varchar(32) NOT NULL DEFAULT '',
  `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `item_category` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `item_id` int(11) unsigned NOT NULL,
  `category_id` int(11) unsigned NOT NULL,
  `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Entity支持嵌套,同时schema.xml中定义了多值属性,所以可以很好的解决一对多的关系。

官方示例中item_category的pk="item_id,category_id",这样会报错,换成pk="item_id"即可。

<dataConfig>
    <dataSource driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/solr" user="root" password="123123" batchSize="-1" />
    <document>
        <entity name="item" pk="id" query="select * from item where isdeleted = 0"
                 deltaImportQuery="SELECT * from item WHERE id=${dataimporter.delta.id}"
                deltaQuery="select id from item where updated > '${dataimporter.last_index_time}'"
                deletedPkQuery="select id from item where isdeleted = 1 AND updated > '${dataimporter.last_index_time}'">
            <field column="name" name="name" />

            <entity name="feature" pk="item_id"   
                    query="select description from feature where item_id = ${item.id}"
                    deltaQuery="select item_id from feature where updated > '${dataimporter.last_index_time}'"
                    parentDeltaQuery="select id from item where id = ${feature.item_id}">
                <field column="description" name="features" />
            </entity>

            <entity name="item_category" pk="item_id"  
                    query="select category_id from item_category where item_id = ${item.id}"
                    deltaQuery="select item_id, category_id from item_category where updated > '${dataimporter.last_index_time}'"
                    parentDeltaQuery="select id from item where id = ${item_category.item_id}">
                <entity name="category" pk="id"  
                        query="select catname from category where id = ${item_category.category_id}"
                        deltaQuery="select id from category where updated > '${dataimporter.last_index_time}'"
                        parentDeltaQuery="select item_id, category_id from item_category where category_id = ${category.id}">
                    <field column="catname" name="cat" />
                </entity>
            </entity>
        </entity>
    </document>
</dataConfig>
  1. ParentDeltaQuery属性决定了,当表发生更新操作的时候,会更新索引,这个特性真是牛X
  2. item表可通过标记删除,来处理记录删除的问题,但其他表都要标记这显然太麻烦了
  3. item_category 关联表记录的删除,不会更新索引,但我们修改时一般是删除旧记录创建新纪录,这样就没问题,前提是必须要选择一个category。
  4. feature 表记录删除,也可以参考上面处理,或者可能你需要update一下item表?
  5. category 表记录的删除比较尴尬,当category表记录删除的时候,一般你还会关联删除iteam_category表(或者外键删除),不知道怎么解决?

注意

Solr可能增量索引有时区的问题,你需要修改一下默认的时区配置,本地模式修改:

vi bin/solr.in.sh
SOLR_TIMEZONE="Asia/Shanghai"

CDH 模式修改Solr Server 的 Java 配置选项

检索

配置优化

SolrCloud

SolrCloud 是Solr为了支持新的分布式特性而命名的。从4.0版本开始支持,提供高可用、分布式集群方案。

Collection:集合。单一索引,作为SolrCloud模式下访问集群的入口,
Shard:分片。单一索引的一部分逻辑表现(也成为分片)
Replica:副本。一个分片的物理表现,
Leader:选举Leader。副本中被选举为Leader提供索引服务的副本。一个分片有多个副本,只能有一个Leader,
SolrCore:索引核心,
Node:节点。Solr的单独实例,一个实例可以管理多个Cores,作为一个集合的一部分。
Cluster:集群,所有节点组成一个集群。

分布式模式下:

Collection 集合作为一个逻辑上索引,会跨越多个服务器,运行在某台服务器上Collection的一部分是一个Core。

单节点:

一个实例会有多个 Collection,因为无法分布式,所以每个Collection都是一个Core。