前言
在Solr中有两种方式索引数据:硬提交和软提交。
软提交是在Solr4.0开始,增加的一个新功能。
那么为什么需要软提交呢?我们先在这里简单介绍一下,后续有详细介绍软提交和硬提交的区别。SolrJ方法
没有软提交之前我们提交索引是这么实现的:
client = new HttpSolrClient("http://localhost:8080/solr/"); //简写
SolrinputDocurnent doc= new SolrinputDocurnent() ;
doc.addF工eld(fieldName , fieldValue) ;
client .add(doc) ;
client.commit();
通过上述代码我们可以看到,我们每次添加一下索引,都要commit()一下,这个操作极其耗费资源,平均耗时600毫秒。
所以我们改用另一种方式来进行提交——软提交。
软提交和硬提交
硬提交是关于持久化的,软提交是关于可见性的。
硬提交
硬提交是将数据持久化到磁盘里面,并且能够查询到这条数据。
硬提交可以通过客户端显式调用实现,也可以通过在solrconfig.xml配置文件中添加相关配置实现。
为了达到灵活提交目的,Solr为硬提交和软提交设计了自动提交策略,自动提交主要靠maxDocs和maxTime两个参数控制,maxTime参数表示每间隔多少毫秒就触发一次索引提交,maxDocs表示当队列中累计了多少个索引文档就触发一次索引提交。两个条件只要满足其中之一即可。
硬提交使用事务日志来获取最新的Document ID,同时对索引文件调用fsync方法确保索引数据写入到磁盘,并且保证即便在断电的极端情况下也不会造成数据丢失。
硬提交它会要求所有的段文件必须立即合并为一个段文件,并重写整个索引,这个操作执行开销很大,不能执行太频繁。段文件合并应该合理配置合并策略,并定期执行索引优化,提升查询性能。
配置文件
<!-- 自动(硬)提交策略 -->
<!-- autoCommit是硬提交, 开启后会进行如下操作: -->
<!-- 生成一个新的tlog文件, 删除旧的tlog文件; -->
<!-- 把内存中缓存的文档fsync(OS内部的函数)到磁盘中, 并创建一个index descriptor, 用来记录各个文档的存储位置;此时就算JVM奔溃或系统宕机, 也不影响这部分数据, 不利之处是: 占用资源较多; -->
<!-- 如果<openSearcher>true</openSearcher>, 就会打开查询器, 让此次硬提交的文档可供搜索. -->
<autoCommit>
<!-- 多少个文档提交一次: 要添加的文档数达到此值时自动触发新的提交 -->
<maxDocs>${solr.autoCommit.maxDocs:1000}</maxDocs>
<!-- 多少毫秒提交一次: 添加文档操作的时间持续到此值时自动触发新的提交, 与maxDocs配置其一即可 -->
<maxTime>${solr.autoCommit.maxTime:1000}</maxTime>
<!-- 如果为false, 提交操作会将最近的更改信息刷新到磁盘, 但不会立即打开查询器 - 也就是说客户端查询不到;
实时性要求高的项目, 需要设置为true - 在6.0之后的版本中默认为true -->
<openSearcher>true</openSearcher>
</autoCommit>
软提交
软提交并没有将数据持久化到硬盘上,只是将更新的索引数据对查询请求可见。
配置文件
<!-- 软提交策略,配置后会进行如下操作 -->
<!-- 把内存中缓存的文档fsync(OS内部的函数)到磁盘中, 但不会创建index descriptor——也就是说各个文档的真实存储位置并没有被记录下来; -->
<!-- 打开文档查询器, 涉及到的索引数据可以被查询到——近实时(NRT)更好; -->
<!-- 软提交不会等待后台合并、整理文档等操作, 只确保了修改的可见行, 没有获取到文档的具体存储位置 —— 也就是说如果此时JVM奔溃或系统宕机, 就找不到这些数据了. -->
<!-- 软提交比硬提交更快, 更能做到近实时查询, 但是如果服务器不稳定, 或JVM奔溃, 会导致提交的数据无法被检索到. -->
<autoSoftCommit>
<maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime>
</autoSoftCommit>
Transaction Log(tlog)
Transaction Log:事务日志,记录了原始文档,用于索引恢复功能。 此处未完待续………………
配置文件
<!-- The default high-performance update handler -->
<!-- 更新处理器 -->
<!-- Solr默认使用的高可用的updateHandler是下面这个: -->
<updateHandler class="solr.DirectUpdateHandler2">
<!-- 索引库的事务日志 -->
<!-- 默认路径: ${SOLR_HOME}/data/tlog. -->
<!-- 启用事务日志用于实时查询、持久化索引数据、Solr Cloud中副本的恢复... -->
<!-- 随着索引库的频繁更新, tlog日志文件会越来越大, 所以建议提交索引时采用硬提交 - 即批量提交的方式 - hard autoCommit. -->
<updateLog>
<!-- dir: 事务日志的存储目录 -->
<str name="dir">${solr.data.dir:}</str>
</updateLog>
<maxPendingDeletes>100000</maxPendingDeletes>
<autoCommit>
<maxDocs>${solr.autoCommit.maxDocs:1000}</maxDocs>
<maxTime>${solr.autoCommit.maxTime:1000}</maxTime>
<openSearcher>true</openSearcher>
</autoCommit>
<autoSoftCommit>
<maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime>
</autoSoftCommit>
</updateHandler>
区别
软提交的速度更快
- 索引软提交之所以比较快速,是因为它只是使用更新的索引数据能够对查询请求可见,但是并没有刷新硬盘上的索引文件或者是硬盘上创建任何文件。如果JVM崩溃了或者服务器断电了,那么上一次硬提交之后的所有索引更新数据将会被丢失。
执行频率
- 软提交可以频繁执行,但是硬提交不可以。
耗时
- 软提交因为不会将数据刷新到硬盘上,索引耗时较少。
吞吐量
- 软提交因为需要频繁执行,所以会降低索引的吞吐量。
相关知识
prepareCommit和commit区别
在Lucene中,索引提交分两个阶段提交,prepareCommit操作属于第一个阶段。第一个阶段会做一些准备工作,比如将队列中待添加和标记为待删除的索引文档刷新到索引文件中,然后同步索引文件、创建并写入段文件,当第一阶段执行完之后,需要显式调用commit结束提交操作,或者调用rollback去回滚提交操作。如果直接调用commit。那么内部会隐式的先调用prepareCommit。