利用solrj API进行微博内容检索

【实验目的】:在172.18.29.185直接调用solrj的API接口完成检索功能,不要使用现成的UI用户界面,不使用web服务。
【参考】:solrj wiki: http://wiki.apache.org/solr/Solrj
【尚有遗留问题】:
测试了本地部署的嵌入服务模式,但一直报错,查了一些网站,还没有找出哪需要配置。

1:关于solr和lucene
Lucene是一个使用Java语言写的全文检索开发包(API),利用它可以实现强大的检索功能。
Solr可以说是Lucene下的一个子项目,是一个完完整整地应用。换句话说,它是一个全文检索服务器。Solr目前的客户端面向的有Java、PHP、Python、C#、Json和Ruby等,有了这些客户端,使用者能很方便地将Solr集成到具体运用中。目前最完善的当属Java客户端Solrj。
a)、Solr服务器的配置在solrconfig.xml中完成,包括对缓存,servlet的个性化配置等等,即系统全局的配置;
b)、索引方法、索引域(字段)等等在schema.xml中完成,这个配置是针对Solr实例的;

[Solr分词顺序]Solr建立索引和对关键词进行查询都得对字串进行分词,在向索引库中添加全文检索类型的索引的时候,Solr会首先用空格进行分词,然后把分词结果依次使用指定的过滤器进行过滤,最后剩下的结果才会加入到索引库中以备查询。分词的顺序如下:

索引
1:空格whitespaceTokenize
2:过滤词StopFilter
3:拆字WordDelimiterFilter
4:小写过滤LowerCaseFilter
5:英文相近词EnglishPorterFilter
6:去除重复词RemoveDuplicatesTokenFilter

查询
1:查询相近词
2:过滤词
3:拆字
4:小写过滤
5:英文相近词
6:去除重复词

以上是针对英文,中文的除了空格,其他都类似

关于schema.xml的配置方法可以借鉴
http://hi.baidu.com/lewutian/item/3d72e939309473bd124b14bd
配置solrconfig.xml,用来配置Solr的一些系统属性,比较重要的一个就是可以通过更改其中的dataDir属性来指定索引文件的存放位置

[Solr的检索运算符]
? “:” 指定字段查指定值,如返回所有值*:*
? “?” 表示单个任意字符的通配
? “*” 表示多个任意字符的通配(不能在检索的项开始使用*或者?符号)
? “~” 表示模糊检索,如检索拼写类似于”roam”的项这样写:roam~将找到形如foam和roams的单词;roam~0.8,检索返回相似度在0.8以上的记录。
? 邻近检索,如检索相隔10个单词的”apache”和”jakarta”,”jakarta apache”~10
? “^” 控制相关度检索,如检索jakarta apache,同时希望去让”jakarta”的相关度更加好,那么在其后加上”^”符号和增量值,即jakarta^4 apache
? 布尔操作符AND、||
? 布尔操作符OR、&&
? 布尔操作符NOT、!、- (排除操作符不能单独与项使用构成查询)
? “+” 存在操作符,要求符号”+”后的项必须在文档相应的域中存在
? ( ) 用于构成子查询
? [] 包含范围检索,如检索某时间段记录,包含头尾,date:[200707 TO 200710]
? {} 不包含范围检索,如检索某时间段记录,不包含头尾,date:{200707 TO 200710}
? \ 转义操作符,特殊字符包括+ – && || ! ( ) { } [ ] ^ ” ~ * ? : \

2:在eclipse环境下利用solrj进行跑下demo
利用solrj的API进行Java编程,需要利用eclipse进行代码调试,所以把工作暂且转移到192.169.76.1服务器上运行,上面有eclipse,重新布置solr环境,采用默认的jetty。
在solrj的官方wiki http://wiki.apache.org/solr/Solrj上说利用内置EmbeddedSolrServer可以跳过对http的访问。
a).启动eclipse建立一个工程org.cBrain.solr;
b).把所需要的Jar包加载到工程中:

此处注意:一定不可以把jar包复制到别的地方去再加载,会出现路径错误!!,这个错误其他地方没有给出提示,正式由于这个错误,在此耽误了好几个小时的调试时间!
c). 往工程文件中敲代码文件;
d). 到../example/ 目录下执行 java –jar start.jar 启动jetty 服务
e). 进行数据索引 java -jar post.jar *.xml;
f). 运行eclipse中的工程。
当query solr时,可以返回content和id:

3:进行100W微博的数据索引
注:调试index的过程中遇到了修改了变量值,而运行过程中还是旧值,这时需要考虑进行refresh并rebuild。Project下拉菜单下的clean操作。

利用lucene的一些jar包进行数据索引。
注:solr 读取数据索引目录,在solrconfig.xml中可以配置solr的索引目录。<dataDir>${solr.data.dir:./solr/data}</dataDir>默认是在目录./solr/data,可以进行修改。这里不修改,先使用默认地址
利用index中的一些代码,把数据从原data文件中解析出来之后利用SolrInputDocument索引到solr的数据库中去。
然后进行查询,以q=“我在围脖”为例,可以发现返回结果数为10,没有精确匹配,可以看到“我在微博”等全部为模糊匹配结果返回。如何设置返回结果数呢?
此时,只是添加了id和content字段,还需要测试其他字段:

Text Send number Receive number Send time Receive time Send region Receive region

先尝试不修改schema.xml文件直接在index函数中调用lucene的数据索引接口进行索引操作。运行时出现错误,在SolrServer.add()时遇到不可知域”fromNumber”,下面修改Solr中的schema.xml文件配置。进入\solr-4.1.0\example\solr\collection1\conf\ 打开schema.xml文件,由于id和content都是默认的:
<field name=”id” type=”string” indexed=”true” stored=”true” required=”true” multiValued=”false” />
<field name=”content” type=”text_general” indexed=”false” stored=”true” multiValued=”true”/>
修改添加其他字段:
<!–modified by jacoxu –>
<field name=”fromNumber” type=”string” indexed=”true” stored=”true” />
<field name=”toNumber” type=”string” indexed=”true” stored=”true” />
<field name=”fromRegion” type=”string” indexed=”true” stored=”true” />
<field name=”toRegion” type=”string” indexed=”true” stored=”true” />
<!–modified by jacoxu –>
保存之后,重新运行java程序,还是出现同样错误,无法找到fromNumber域,重新启动jetty后运行OK。
接下来检索fromNumber的相关内容<微博>:
现在索引到的字段有:id, content, fromNumber, toNumber, fromRegion, toRegion
接下来测试不需要通过Http端口访问的EmbeddedSolrServer. 之前的通过Http开启服务器的函数为:
String url = “http://localhost:8983/solr”;
HttpSolrServer server = new HttpSolrServer( url );
server.setMaxRetries(1);
server.setConnectionTimeout(5000); //5s to establish TCP
server.setParser(new XMLResponseParser());
server.setSoTimeout(1000); //socket read timeout
server.setDefaultMaxConnectionsPerHost(100);
server.setMaxTotalConnections(100);
server.setFollowRedirects(false);
//server side must support gzip or deflate for this to have any effect
server.setAllowCompression(true);
替换为本地的EmbeddedSolrServer 服务:
System.setProperty(“solr.solr.home”, “C:\\jacoxu\\test\\2013-02-25_solr\\” +
“solr-4.1.0\\solr-4.1.0\\example\\solr”);
CoreContainer.Initializer initializer = new CoreContainer.Initializer();
CoreContainer coreContainer = initializer.initialize();
EmbeddedSolrServer server = new EmbeddedSolrServer(coreContainer, “”);
执行程序出现错误:
修改solrconfig.xml(同样在\solr-4.1.0\example\solr\collection1\conf\目录下)中的内容?查看wiki,需要开启哪项?还没有找到。暂且放下。
放大数据索引文档数,由1K增加到100W,这时有200M的数据量,java的虚拟内存不足而溢出,考虑是否需要对server进行分批add, 也可以直接在eclipse中修改Java的虚拟内存:
不过这种方法显然不解决大数据文件问题,还是分批进行比较好,可设置add一万个文档后进行一次add();操作。但add操作最好还是利用集合Collection ArrayList把doc进行批量add操作,不然会索引速度很慢。
此处,我们声明一个集合docs,每10W个doc进行一次add操作,并利用docs.clear清空相应docs。
注意,field “id”相当于hash中的key是独一无二且必有的。当add操作时会先检测id。Server.commit操作只要执行,当前就会直接跳出数据add阶段,开始下一步查询等操作。

这时经过多次实验,已保存了很多数据索引,要考虑如何进行数据索引删除。

server.deleteByQuery(“*:*”);
server.commit();

检索的过程中出现了一些警示,不过倒是没有产生任何错误,不知道这个SocketTimeout有什么影响。。。

附录,主文件代码:

  1. import java.io.IOException;   
  2. import java.util.Iterator;   
  3.   
  4. import org.apache.lucene.index.DocsAndPositionsEnum;   
  5. import org.apache.solr.client.solrj.SolrQuery;   
  6. import org.apache.solr.client.solrj.SolrServerException;   
  7. import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;   
  8. import org.apache.solr.client.solrj.impl.HttpSolrServer;   
  9. import org.apache.solr.client.solrj.impl.XMLResponseParser;   
  10. import org.apache.solr.client.solrj.response.QueryResponse;   
  11. import org.apache.solr.common.SolrDocument;   
  12. import org.apache.solr.core.CoreContainer;   
  13.   
  14. import org_cbrain_lucene_process.generateData;   
  15. import org_cbrain_lucene_process_test.indexTest;   
  16.   
  17. public class searcherBaseonSolrj {   
  18.     public static void main(String[] args) throws SolrServerException, IOException   
  19.     {   
  20.         //********!!!!!!!!!!**********//   
  21.         boolean hasIndex = true;   
  22.         boolean deleteData = false;   
  23.   
  24.         //********!!!!!!!!!!**********//   
  25.         //Initialize httpSolrServer   
  26.         try {   
  27. ///*   
  28.             String url = “http://localhost:8983/solr”;   
  29.             HttpSolrServer server = new HttpSolrServer( url );   
  30.             server.setMaxRetries(1);   
  31.             server.setConnectionTimeout(5000); //5s to establish TCP   
  32.             server.setParser(new XMLResponseParser());   
  33.             server.setSoTimeout(2000); //socket read timeout   
  34.             server.setDefaultMaxConnectionsPerHost(100);   
  35.             server.setMaxTotalConnections(100);   
  36.             server.setFollowRedirects(false);   
  37.             //server side must support gzip or deflate for this to have any effect   
  38.             server.setAllowCompression(true);   
  39. //*/   
  40.             //EmbededSolrServer   
  41. /*  
  42.             System.setProperty(“solr.solr.home”, ”C:\\jacoxu\\test\\2013-02-25_solr\\” +  
  43.                 solr-4.1.0\\solr-4.1.0\\example\\solr”);  
  44.                       
  45.             CoreContainer.Initializer initializer = new CoreContainer.Initializer();  
  46.             CoreContainer coreContainer = initializer.initialize();  
  47.                       
  48.             EmbeddedSolrServer server = new EmbeddedSolrServer(coreContainer, ”");  
  49. */     
  50.             SolrQuery query = new SolrQuery();   
  51. //          query.setQuery(“*:*”);   
  52.             query.setQuery(“新店爆款!”);   
  53. //          query.setQuery(“fromNumber:13473043030″);   
  54. //          query.setQuery(“fromRegion:中国 黑龙江 哈尔滨”);   
  55.                
  56.             //delete data   
  57.             if (deleteData) {   
  58.                 System.out.println(“开始删除所有数据索引…”);   
  59.                 server.deleteByQuery(“*:*”);   
  60.                 System.out.println(“删除数据索引完毕!”);   
  61.             }   
  62.             //index data   
  63.             if(!hasIndex) {   
  64. //              indexTest indexData = new indexTest();   
  65. //              indexData.indexData(args);   
  66. //              server.add(indexData.docs);   
  67. //              server.commit();//update response   
  68.                 System.out.println(“开始对数据进行索引…”);   
  69.                 generateData indexData = new generateData();   
  70.                 indexData.Indexdata(server);   
  71.                 try {   
  72.                     server.optimize();   
  73.                     server.commit();   
  74.                 } catch (Exception e) {   
  75.                     // TODO: handle exception   
  76.                     e.printStackTrace();   
  77.                 }   
  78.                 System.out.println(“数据索引完毕!”);   
  79.             }   
  80.                
  81.             //Query the server   
  82.             QueryResponse rsp = server.query(query);   
  83.                
  84.             //Get the results   
  85.             Iterator<SolrDocument> itDocs = rsp.getResults().iterator();   
  86.                
  87.             System.out.println(“查到相关文档个数: ” + rsp.getResults().getNumFound());   
  88.             System.out.println(“查询所用时间为: ” + rsp.getQTime());   
  89.             if (rsp.getResults().getNumFound() > 10) {   
  90.                 System.out.println(“显示前10项相关结果”);   
  91.             }   
  92.             if (!itDocs.hasNext()) {   
  93.                 //如果没有任何返回结果   
  94.                 System.out.println(“no any result! ”);   
  95.             }   
  96.             while (itDocs.hasNext()) {   
  97.                 SolrDocument resultDoc = itDocs.next();   
  98.                    
  99.                 String content = (String) resultDoc.getFieldValue(“content”);   
  100.                 String id = (String) resultDoc.getFieldValue(“id”);    
  101.   
  102.                 System.out.println(“Content: ” + content + “  Id: ” + id);   
  103.             }   
  104.         } catch (Exception e) {   
  105.             System.out.println(“请检查jetty服务器或端口是否开启!”);   
  106.             e.printStackTrace();   
  107.         }   
  108.     }   
  109. }  

利用solrj API进行微博内容检索》上有 2 条评论

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>