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之困的更多相关文章

  1. solr服务中集成IKAnalyzer中文分词器、集成dataimportHandler插件

    昨天已经在Tomcat容器中成功的部署了solr全文检索引擎系统的服务:今天来分享一下solr服务在海量数据的网站中是如何实现数据的检索. 在solr服务中集成IKAnalyzer中文分词器的步骤: ...

  2. Solr 排除查询

    前言 solr排除查询也就是我们在数据库和程序中经常处理的不等于,solr的语法是在定语前加[-].. StringBuilder sbHtml=new StringBuilder(); shBhtm ...

  3. Solr高级查询Facet

    一.什么是facet solr种以导航为目的的查询结果成为facet,在用户查询的结果上根据分类增加了count信息,然后用户根据count信息做进一步搜索. facet主要用于导航实现渐进式精确搜索 ...

  4. [Solr] (源) Solr与MongoDB集成,实时增量索引

    一. 概述 大量的数据存储在MongoDB上,需要快速搜索出目标内容,于是搭建Solr服务. 另外一点,用Solr索引数据后,可以把数据用在不同的项目当中,直接向Solr服务发送请求,返回xml.js ...

  5. sorl6.0+jetty+mysql搭建solr服务

    1.下载solr 官网:http://lucene.apache.org/solr/ 2.目录结构如下 3.启动solr(默认使用jetty部署) 在path路径下将 bin文件夹对应的目录加入,然后 ...

  6. Solr Facet 默认值

    前言 今天在用Solr Facet遇到了默认值的问题,我用Facet.field查询发现数据总共100条,刚开始没有注意,发现少个别数据,但是用这几个个别的id查询又能查出来数据.才发现是Facet默 ...

  7. solr添加多个core

    在D:\solr\solr_web\solrhome文件夹下: 1)创建core0文件夹 2)复制D:\solr\solr_web\solrhome\configsets\basic_configs/ ...

  8. solr定时更新索引遇到的问题(SolrDataImportProperties Error loading DataImportScheduler properties java.lang.NullPointerException)

    问题描述 报如下错误,很显然,问题原因:空指针异常: ERROR (localhost-startStop-1) [   ] o.a.s.h.d.s.SolrDataImportProperties ...

  9. Solr实战:使用Hue+Solr实现标签查询

    公司最近在研究多条件组合查询方案,Google的一位技术专家Sam和我们讨论了几个备选方案. Sam的信: 我做了进一步研究,目前有这么几种做法: 1) 最直接粗暴,只做一个主index,比如按行业+ ...

随机推荐

  1. 【原】Eclipse部署Maven web项目到tomcat服务器时,没有将lib下的jar复制过去的解决办法

    我们在做web开发是,经常都要在eclipse中搭建web服务器,并将开发中的web项目部署到web服务器进行调试,在此,我选择的是tomcat服务器.之前部署web项目到tomcat进行启动调试都很 ...

  2. jquery 常用获取值得方法汇总

    jquery取radio单选按钮的值$("input[name='items']:checked").val();jquery radio取值,checkbox取值,select取 ...

  3. (转)SQL Server创建索引

    什么是索引拿汉语字典的目录页(索引)打比方:正如汉语字典中的汉字按页存放一样,SQL Server中的数据记录也是按页存放的,每页容量一般为4K .为了加快查找的速度,汉语字(词)典一般都有按拼音.笔 ...

  4. 找不到原始安装光盘的佳能EOS Utility的下载和安装

    佳能EOS Utility的下载和安装   佳能很有意思,在官方网站上提供的数码相机驱动程序,只是“升级版”,而不是原始安装版.如果我有安装光盘,还去网上下载驱动干吗?解决方案:1,从佳能官方网站上下 ...

  5. java多线程知识汇总(三)如何选择锁?如何加锁

    1.锁,保证的是被锁的代码,一次执行完毕才能被其他线程执行,锁保证了一个线程执行过程中不被其他线程打断.以保证数据的准确性. 2.数据的读写过程,是有冲突的,当一个线程正在读数据,另一个线程正在写同一 ...

  6. ArcGIS for Android地图上实际距离与对应的屏幕像素值计算

    本篇文章主要介绍了"ArcGIS for Android地图上实际距离与对应的屏幕像素值计算",主要涉及到ArcGIS for Android地图上实际距离与对应的屏幕像素值计算方 ...

  7. 【java】【mysql】存储微信表情emoji表情

    java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x94' for colum n 'name' at row 1 at com ...

  8. maven编译错误,警告: BASE64Decoder是内部专用 API, 可能会在未来发行版中删除

    修改红色部分版本号为2.3.2              <plugin>                 <groupId>org.apache.maven.plugins& ...

  9. llvm中如何利用分支概率和基本块频率估计

    1. 背景 llvm自2.9版以后,已经集成了对分支概率和基本块频率的静态分析. 分支概率(branch probability)是指在程序的控制流图中,从控制流从一个基本块A到其任意后继基本块Si的 ...

  10. OpenShift 容器日志和应用日志分离问题

    一般来说应用日志和容器日志一样输出到console,这样oc logs的时候就能把所有的获取到,但这种模式下输出的日志比较多,问题定位不方便,更多的时候开发人员只想通过应用日志来查看定位问题就够了,所 ...