我的使用经历
使用solr3.6版本,配合自己用lucene3.6建立的索引,搭建了一个搜索服务,前台通过http访问solr服务,获取由solr排序后的结果集,进行展示。环境是linux ubuntu,servlet容器是tomcat。这个搜索服务是提供给php开发人员使用的。根据我现在对solr的理解和使用感受,我想说说solr这玩意儿的实用性。
我对solr的理解
solr包装了lucene之后,将整个搜索项目放入了Servlet容器里(jetty或者tomcat),变成一个web service。与lucene不同的是,solr把索引的定制,建立,更改,查询全部放入自己的配置文件里。从scheme.xml和solrconfig.xml两个配置文件,我认为就看到了solr可以做到的一切。
具体说,scheme.xml里用户主要可以配置:分词工具,每个field类型采用的solr类,索引结构(field,STORE,ANALYZE),默认搜索域,默认与或规则。作为一名使用过lucene的开发者,在看到官方一些solr构建索引的方式之后,我果断放弃了solr来建索引。solr多种方式建立索引的方式,是为了适合不同的场景和使用需求,无论是读xml,csv文件数据,和数据库交互读数据还是http方式的json更新索引,都让我觉得不底层。当然,这是solr包装了lucene后的结果。我觉得这种形式比较方便做工具的整合,比如你用Nutch或者别的工具爬数据,然后分析整理后变成一个http url或者存成了csv文件,紧接着通过Solr自动去读取建立索引,最后再用solr这个web服务提供搜索服务。而至少对于我来说,我想做的是我自己更细致地来处理数据的建索引过程。借着solr与lucene的兼容性,我自己用lucene建索引并放入solr的路径里提供搜索。
再看solrconfig.xml,它可以配置:索引文件路径,solr的三种缓存(filterCache, queryResultCache, documentCache),索引更新及参数配置,索引查询时候的各种参数(默认字段,是否高亮,过滤字段,字段权重,打分公式等)。
的确,通过solr的这两个配置,一个搜索服务很可以简单搭建起来,但是我定义solr只是一个数据库层之上的东西,solr之上的代码如果仅仅通过solr的url传参方式得到搜索结果,只能是得到一个很通用的搜索结果集,无法个性化定制搜索。如果要更针对个性化的需求,在solr和前台之间还需要一层中间件,这层中间件应该需要做这些事:
1. 接受到前台传来的搜索词,对词进行个性化处理和赋权
2. 对搜索请求分发到不同索引文件和字段进行搜索(这里不是指分布式分发,只是逻辑上分发到不同索引块)
3. 从solr获得结果之后,再进行一些局部的排名和优化,甚至可以再过滤处理
我认为只要你自己可以写servlet,完全可以用lucene和servlet搭建一个比solr更具实用性和个性的搜索服务,而不像solr那么通用和高层(针对api的底层而言)。solrj提供了solr的java api,可以使用solr的api来类似lucene一样进行各种query的查询和处理,但是如果没有solrj呢?比如php,就只能通过solr的url做一些参数的拼凑,获得返回结果,实在有点太通用了。或者说,solr根本不是一个搜索引擎服务,否则是黑了“搜索引擎”这个词。它只是数据库之上的一层数据索引层,其他的东西你自己继续添加吧。
其实就我看到的网上的一些solr资料,无非是一些solr安装啊,配置啊,结合数据库,结合nutch搭建了一个服务啊之类的,总结就是都很通用,技术性都不强,不能成为搜索引擎。只是一个基于数据库数据的一个打分ranking处理而已。
总结
solr的确配置方便,通过配置可以解决大部分问题,但是这东西太通用了,为什么感觉是给非码农用的?为什么我使用过lucene之后,就不想用它建索引,而宁可自己再写一个工程来做建索引这件事情?solr只是一个能放入servlet容器的东西而已?对非java的语言,除了改solr源码,你还能怎样定制自己的搜索?
说明,我使用的ide是vs2008
1. 工程设置为debug
内存泄露的检测一般在debug模式下进行
2.在需要检查内存泄露的cpp头部加上
#ifdef _DEBUG #define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> #define new new(_NORMAL_BLOCK, __FILE__, __LINE__) #endif
3.代码中插入这么一句话
EnableMemLeakCheck();
inline void EnableMemLeakCheck() { _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF); }
4.然后就可以在输出中看泄露情况了
举个例子,例子中我用newEx表示的上述宏定义中的new
int _tmain(int argc, _TCHAR* argv[]) { EnableMemLeakCheck(); int num = 10; byte **p = newEx byte *[num]; for (int i = 0; i < num; i ++) { Sleep(1); *p = newEx byte[i]; } long *pl = newEx long[100]; while(1) { Sleep(100); } return 0; }
输出中显示的内容(debug下运行程序,然后点叉叉关闭程序)
memory leaks!
Dumping objects ->
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(101) : {124} normal block at 0x00295CB8, 400 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : {122} normal block at 0x00294C30, 9 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : {121} normal block at 0x00294BE8, 8 bytes long.
Data: < > CD CD CD CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : {120} normal block at 0x00299F88, 7 bytes long.
Data: < > CD CD CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : {119} normal block at 0x00299F40, 6 bytes long.
Data: < > CD CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : {118} normal block at 0x00299EF8, 5 bytes long.
Data: < > CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : {117} normal block at 0x00299EB8, 4 bytes long.
Data: < > CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : {116} normal block at 0x00299E78, 3 bytes long.
Data: < > CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : {115} normal block at 0x00299E38, 2 bytes long.
Data: < > CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : {114} normal block at 0x00299DF8, 1 bytes long.
Data: < > CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : {113} normal block at 0x00299DB8, 0 bytes long.
Data: <> 励p
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(88) : {112} normal block at 0x00299D50, 40 bytes long.
Data: <0L) > 30 4C 29 00 CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
有文件名和行号,先申请的后释放。
扩展:
实际上是使用了另外的new,在dbgnew.cpp中,列一个例子说明:
void *__CRTDECL operator new[]( size_t cb, int nBlockUse, const char * szFileName, int nLine ) _THROW1(_STD bad_alloc) { void *res = operator new(cb, nBlockUse, szFileName, nLine ); RTCCALLBACK(_RTC_Allocate_hook, (res, cb, 0)); return res; }
例如:
char new_index_recorder_file_name[1024 * 1024][256]; class new_index_recorder{ public: new_index_recorder(char* file, int line) : file(file), line(line){ } operator char*(){ static unsigned int index; sprintf(new_index_recorder_file_name[index], "%s(%d) : %d ", file, line, index++); return new_index_recorder_file_name[index]; } private: char* file; int line; };
当然,也可以用函数来返回char*指针
int g_count = 0; class OperNew { public: OperNew() { g_count ++; pC = new char[20]; memset(pC, 0, 10); sprintf(pC, "No.%d", g_count); } char* GetChar() { return pC; } private: char * pC ; };
这样就能返回自定义的内容了。本次的返回加上了一个构造时候的序号,当然也可以添加时间等。结果如下:
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(95) : 11 (95) : {123} normal block at 0x002B4C78, 400 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : 10 (92) : {122} normal block at 0x002B4C30, 9 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : 9 (92) : {121} normal block at 0x002B4BE8, 8 bytes long.
Data: < > CD CD CD CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : 8 (92) : {120} normal block at 0x002B9F88, 7 bytes long.
Data: < > CD CD CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : 7 (92) : {119} normal block at 0x002B9F40, 6 bytes long.
Data: < > CD CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : 6 (92) : {118} normal block at 0x002B9EF8, 5 bytes long.
Data: < > CD CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : 5 (92) : {117} normal block at 0x002B9EB8, 4 bytes long.
Data: < > CD CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : 4 (92) : {116} normal block at 0x002B9E78, 3 bytes long.
Data: < > CD CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : 3 (92) : {115} normal block at 0x002B9E38, 2 bytes long.
Data: < > CD CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : 2 (92) : {114} normal block at 0x002B9DF8, 1 bytes long.
Data: < > CD
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(92) : 1 (92) : {113} normal block at 0x002B9DB8, 0 bytes long.
Data: <> h鴌
e:\project\test\test_mem_leak\test_mem_leak\test_mem_leak.cpp(88) : 0 (88) : {112} normal block at 0x002B9D50, 40 bytes long.
Data: <0L+ > 30 4C 2B 00 CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
程序“[8796] test_MEM_LEAK.exe: 本机”已退出,返回值为 -1073741510 (0xc000013a)。
小提示:
将输出文件拷贝到UE中,然后查找泄露行号出现的次数,可以计算出泄露的数目。
解决方法:在ios5以上版本,应用程序加载时,需要一个 root view controller ,所以需要编写代码
_rootViewController = [[RootViewController alloc] init];
self.window.rootViewController = _rootViewController;