Solr之困
http://www.kafka0102.com/2010/08/319.html重写公司的站内搜索。经过前期一段时间对lucene和solr的熟悉,最后决定使用Solr作为新系统的基础框架。现在已经是第一阶段开发的后期,核心代码行数有11000+(不包含admin及client等)。现已实现的功能要比已有系统要丰富些,但综合比较两个系统总的代码量,其实新系统并不多得太多。新系统使用Solr代替了已有系统实现的部分功能,这减少了新系统的代码量,同是新系统实现了已有系统不具有的功能,也增加了一些代码量。开发的这段时间,因为新系统中很多代码是独立于Solr的,所以和Solr的交互也是时断时续,以使得即便到了开发后期我还能发现Solr实现的一些细节带给我的困扰。
抛开我所做的系统来说,如果要选择一个站内搜索解决方案,Solr在某些场景下可能是个很不错的选择。因为Solr提供了Web server支持通过Http来更新索引、重建索引、查询等功能,如果需求对上Solr,甚至可以不需要基于Solr做二次开发就直接满足需要。多美妙的事情阿。不过,如果你需要些高级功能,那么可能你需要基于Solr做些工作了。比如,如果索引库很大,可以将索引库拆成多个shard,查询时对多个shard进行,这个功能Solr是支持的;不过,建索引的事情就需要自己搞定了,比如在Solr前面加个Proxy(或者只是个库函数),在建索引时根据特定的策略提交到不同的shard上。这个其实也还好了,但如果我需要一个涉及到多个索引库(各索引库有不同的schema)的查询,比如要做整站搜索,那么Solr的shard查询就用不上了,因为它必须要求各shard的schema一致。而我要做的实际是个通用搜索,这样的问题就有些接踵而至了。尽管和Solr磨合的过程花了不少时间,涉及到对它提供的功能、设计、源码的理解等等,并且有时还要妥协它开发,有时还要舍弃它已实现的功能而另起炉灶。但不可否认的是,对于初涉站内搜索开发的我来说,使用Solr并不是太坏的选择,从中也学到了Solr优秀的地方,同时也看到它不足的地方,都是收获。本文会简单的总结下个人在应用Solr过程中一些不是很爽的地方,爽的地方姑且按下不表。
Solr实现上有个核心东西,就是SolrCore。每个SolrCore对应着一个索引库,几乎所有的操作都是针对单个SolrCore进行的,似乎Solr的初衷就是如此,并没有考虑到多个SolrCore之间的关联。所以,可以看到的是,每个SolrQueryRequest都会关联到一个SolrCore,SolrRequestHandler的获得也是从SolrCore取得的。这糟糕的设计使得,当需要对多个SolrCore做管理时,Solr不得不做出CoreAdminHandler,它虽然实现了SolrRequestHandler接口,但它是脱离于SolrCore的,使得配置上也和其他handler不一样。而Solr的shard查询的支持就更糟糕,它要求shard的SolrCore的schema都是一致的,而不能查询异构的SolrCore。为了解决这个问题,我在Solr基础上加了个VirtualCore(这个概念现在看起来不是很好,或许IndexCore会更好些),VirtualCore里面可以包含一个或多个SolrCore,而很多操作就不是针对SolrCore而是针对VirtualCore了。比如索引库index被拆分成index.0、index.1、index.2,无论索引还是查询,客户端只需要向系统针对core=index进行请求,无需关心index被系统拆分成几个库,这些库被如何分布,系统会通过配置把这些事情做好。对于整站多个库的联合查询,就是针对多个VirtualCore进行,可以通过配置指定各个VirtualCore的请求参数而不需要像Solr那样有严格的约束。
引入了VirtualCore,使得Solr的一些实现不能得手的使用上。首当其冲的就是它的SearchHandler,我不得不在它的基础上重写了一个,它的shard请求异常处理策略也很有问题,如果shard请求中的某个出现异常,它就不会返回结果,这样做的好处是保证返回结果的全局准确性,但却降低了可用性。这里也需要考虑到查询结果cache的问题,如果在Solr前面加了查询结果Cache,那么Solr这种准确性要求就是有必要的。但在我的实现中,是可以有多少shard返回就处理多少,但在异常的情况下就不做查询结果cache处理。
VirtualCore也使得Solr强悍的DIH也用不上了,但即便没有VirtualCore,DIH也很难解决单点提交多个shard索引的问题。DIH直接对索引的SolrCore做重建索引处理,并没有对重建索引过程提供灵活的hook(尽管它确实提供了一些hook)。就我的需求来说,我希望每索引一个文档同时会根据一定的策略来更新摘要数据库,我浏览了DIH的文档和代码,似乎很难做到。而且,DIH是直接在现有索引上做重建的,如果重建时间很长或者出现问题,使得同时进来的更新索引被阻塞,就会影响到正常的服务。
Solr对配置文件的把握上也不够好。Solr对solrconfig.xml文件提供了Java属性值替换配置文件变量,但solr.xml却没有支持,使得线上线下配置文件中充斥着不同的绝对路径。也有好的一方面,比如schema.xml支持Xinclude,使得多个索引库的schema.xml可以共用相同的field type定义。不过,如果多个索引库的schema能集中在一个文件而不是散落成多个文件,管理起来会更方便。这样的问题同时也存在于solrconfig.xml,尽管solrconfig.xml大多数项的配置都是通用的,不过多个索引库时,searcher的warm请求参数可能就会不一样,这使得我在考虑安排时间改写它的默认Lisnter的实现。
Solr的索引复制有一个细节,那就是master和slave保持长连接,master通过调用OutputStream的flush方法不断把数据发送给slave,如果使用Servlet容器,通过Servlet得到OutputStream这样做没什么问题,但如果使用Netty作为服务器框架,并且使用Netty的http实现,那就实现不了这个效果。这使得我不得不放弃Netty改用Jetty了。
再回到查询上,Solr的SearchHandler只会得到doc id list,而不会得到需要的所请求的字段内容,它是在ResponseWriter输出时根据doc id从IndexReader得到需要的字段。在我的设计中,索引只会存储逻辑主键id,得到逻辑主键id后再从另外的摘要库把其他字段取回(或者就是返回id列表给客户端),但我显然需要在ResponseWriter输出前做完这些事情,这使得我并不得不修改request需要返回的字段列表为空。而这个ResponseWriter是需要和SolrCore的schema绑定的,结果对于并不存在的VirtualCore,我还不得不使用上配置为空并且没有索引的fake schema蒙混过去。
还是关于配置,Solr复制slave端配置的master url需要指定参数core,这使得每个SolrCore都有不同的master url而不能共用一个solrconfig.xml,而我真的很希望它们能共用一个solrconfig.xml。其实这个core参数在ReplicationHandler中完全可以得到,Solr没这么做的一个可能的原因是,它支持的请求url格式是http://host/corename/qt?xx=dd,把corename作为url path的一部分让我用起来很不爽,所以我把请求的格式格式改成:http://host/qt?core=aaa&xx=dd,并出下策把Solr和复制相关的代码拷过来,增加了几行代码完事。
问题当然还有,但就像上面提到的,遇到问题总要找个解决方案,尽管有的方案看起来有些二。在回想上面提到的问题之后,我对现在完成的产出的可用性有些怀疑,我到现在还没有完整的测试过这个系统,所以,它还需要我更仔细的打磨。值得庆幸的是,随着对Solr了解的深入,我能更好的驾驭它了。
==================== 华丽的终止符 ===================
Solr之困的更多相关文章
- solr服务中集成IKAnalyzer中文分词器、集成dataimportHandler插件
昨天已经在Tomcat容器中成功的部署了solr全文检索引擎系统的服务:今天来分享一下solr服务在海量数据的网站中是如何实现数据的检索. 在solr服务中集成IKAnalyzer中文分词器的步骤: ...
- Solr 排除查询
前言 solr排除查询也就是我们在数据库和程序中经常处理的不等于,solr的语法是在定语前加[-].. StringBuilder sbHtml=new StringBuilder(); shBhtm ...
- Solr高级查询Facet
一.什么是facet solr种以导航为目的的查询结果成为facet,在用户查询的结果上根据分类增加了count信息,然后用户根据count信息做进一步搜索. facet主要用于导航实现渐进式精确搜索 ...
- [Solr] (源) Solr与MongoDB集成,实时增量索引
一. 概述 大量的数据存储在MongoDB上,需要快速搜索出目标内容,于是搭建Solr服务. 另外一点,用Solr索引数据后,可以把数据用在不同的项目当中,直接向Solr服务发送请求,返回xml.js ...
- sorl6.0+jetty+mysql搭建solr服务
1.下载solr 官网:http://lucene.apache.org/solr/ 2.目录结构如下 3.启动solr(默认使用jetty部署) 在path路径下将 bin文件夹对应的目录加入,然后 ...
- Solr Facet 默认值
前言 今天在用Solr Facet遇到了默认值的问题,我用Facet.field查询发现数据总共100条,刚开始没有注意,发现少个别数据,但是用这几个个别的id查询又能查出来数据.才发现是Facet默 ...
- solr添加多个core
在D:\solr\solr_web\solrhome文件夹下: 1)创建core0文件夹 2)复制D:\solr\solr_web\solrhome\configsets\basic_configs/ ...
- solr定时更新索引遇到的问题(SolrDataImportProperties Error loading DataImportScheduler properties java.lang.NullPointerException)
问题描述 报如下错误,很显然,问题原因:空指针异常: ERROR (localhost-startStop-1) [ ] o.a.s.h.d.s.SolrDataImportProperties ...
- Solr实战:使用Hue+Solr实现标签查询
公司最近在研究多条件组合查询方案,Google的一位技术专家Sam和我们讨论了几个备选方案. Sam的信: 我做了进一步研究,目前有这么几种做法: 1) 最直接粗暴,只做一个主index,比如按行业+ ...
随机推荐
- Unity ScriptObject创建Asset文件
创建ScriptObject可以创建带序列化的资源,只保存数据不用绑定在游戏对象上.创建出来的本子资源可以通过资源加载到游戏里使用.这里介绍一下使用Resources加载. 创建好的asset文件也可 ...
- android基础篇------------java基础(11)(文件解析xml and Json )
一:xml文件解析 首先看一下:我们要解析的内容: <?xml version="1.0" encoding="gbk" ?> - <book ...
- 【mysql】mysql查询 A表B表 1对多 统计A表对应B表中如果有对应,则返回true否则false作为A表查询结果返回
A表:goods_type B表:brand_config A:B = 1:N 一种商品类型 对应多条 品牌配置 ======================================== 需求 ...
- ArcGIS For Android ExportTileCache应用
说明:从ArcGIS For Android10.2.4 ,開始支持下载在线地图服务切片缓存到移动设备本地.以便离线时进行地图浏览.本文章摘要介绍,使用自己公布的服务时,须要注意的内容. 一.首先公布 ...
- 解决 PHP Fatal error: Call-time pass-by-reference has been removed
PHP在升级到5.4版本的php可能会出现这种错误: 如果这样使用函数(或者类)的话,会产生一个 PHP Fatal error:foo(&$var);实际上,这样用法在php5.3中就会有提 ...
- (转)SqlServer里DateTime转字符串
原文:http://www.cnblogs.com/kimbosung/p/4515670.html ), )::: ), ): :::953PM ), ): ), ): ), ): ), ): :: ...
- mac的dns缓存查询和清除
1.清楚dns缓存 dscacheutil -flushcache 2.查询nslookup
- iOS:使用贝塞尔曲线绘制图表(折线图、柱状图、饼状图)
1.介绍: UIBezierPath :画贝塞尔曲线的path类 UIBezierPath定义 : 贝赛尔曲线的每一个顶点都有两个控制点,用于控制在该顶点两侧的曲线的弧度. 曲线的定义有四个点:起始点 ...
- informatica powercenter学习笔记(二)
LOOKUP TRANSFORMATION的使用点评: LOOKUP基本用法不熟的话请参考下附属信息. 用法感受: 1 LOOKUP的作用跟我们以前在EXCEL的函数功能类似,就是隔表取值.优点就是用 ...
- Orchard运用 - 整合Disqus评论插件
评论对于博客系统那是必须具备的一个功能,Orchard本身也默认实现了评论模块,你可以集成到其他内容,比如博客随笔,不过觉得有点寒碜,样式有点呆板.幸运的是,你可以简单集成第三方评论插件,比如Disq ...