使用Solrj管理Solr索引

2023-12-05 22:58
文章标签 使用 管理 索引 solrj solr

本文主要是介绍使用Solrj管理Solr索引,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Solrj是Solr搜索服务器的一个比较基础的客户端工具,可以非常方便地与Solr搜索服务器进行交互,最基本的功能就是管理Solr索引,包括添加、更新、删除和查询等。对于一些比较基础的应用,用Solj基本够用,而且你可以非常容易地通过使用Solrj的API实现与Solr搜索服务器进行交互,实现对Solr的基本管理功能。如果你的应用比较复杂,可以扩展Solrj来满足需要。

下面是一个使用Solrj的API实现与Solr服务器交互的工具类SolrPostServer,能够实现索引的添加、更新、删除和查询功能。SolrPostServer类中两个内部类是与访问MongoDB的配置和工具。

在实际应用中,对于是否进行commit,可以有两种方式:

  • 一种是直接在客户端进行计算,亦即,进行索引时计算添加的文档数,满足设置的值则进行手动commit,这种方式比较灵活,你可以根据搜索服务器的运行状况选择合理的commit文档数量;
  • 另一种是,直接在Solr搜索服务器上进行配置,一般来说,对索引进行大批量更新,一般不会选择在搜索服务器业务繁忙的时候进行,所以能够自动进行commit也便利了对索引的管理,更新文档可以完全可以实现自动化处理。
在Solr服务器端进行配置有关commit的功能,可以在requestHandler中进行配置,示例如下:
	<requestHandler name="/update" class="solr.XmlUpdateRequestHandler"><maxPendingDeletes>10000</maxPendingDeletes><autoCommit><maxDocs>20</maxDocs><maxTime>86000</maxTime></autoCommit></requestHandler>
上面autoCommit中的maxDocs指定的pending多少个文档后执行一次commit,而maxTime指定了多长时间间隔进行一次commit,一般这两个选项只需要配置一个即可满足需要。另外,每次commit会将最近的更新生效,但是如果一次commit操作尚未完成,又达到了下一次commit的时刻,这样做会严重影响索引的吞吐量。
在Solr 4.0将会实现一种基于“软自动提交”(soft auto commit)的功能,它会根据当前的系统上下文决定是否提交(简单的情况就是,确保每次commit完成,也就是最近的索引数据更新已经更新同步到磁盘上之后再自动执行下一次commit)。

实现代码如下所示:

package org.shirdrn.solr.solrj;import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;import org.apache.commons.httpclient.HttpClient;
import org.apache.log4j.Logger;
import org.apache.lucene.document.Document;
import org.apache.solr.client.solrj.ResponseParser;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.client.solrj.impl.XMLResponseParser;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.SolrParams;import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;/*** Solr server for indexes operations.* * @author shirdrn* @date   2011-12-20*/
public class SolrPostServer {private static final Logger LOG = Logger.getLogger(SolrPostServer.class);private CommonsHttpSolrServer server; private ResponseParser responseParser;private MongoConfig mongoConfig;private String[] collectionNames;private  int maxCommitCount = 100;private boolean manualOptimize = true;private boolean manualCommit = false;private Collection<SolrInputDocument> docContainer = new ArrayList<SolrInputDocument>();private static int totalCount = 0;public SolrPostServer(String url, HttpClient httpClient, MongoConfig mongoConfig) {try {if(httpClient==null) {server = new CommonsHttpSolrServer(url);server.setSoTimeout(500000);  // socket read timeoutserver.setConnectionTimeout(5000);  server.setDefaultMaxConnectionsPerHost(10);  server.setMaxTotalConnections(100);server.setAllowCompression(true);  server.setMaxRetries(1); // defaults to 0.  > 1 not recommended. } else {server = new CommonsHttpSolrServer(url, httpClient);}} catch (MalformedURLException e) {e.printStackTrace();}this.mongoConfig = mongoConfig;initialize();}/*** Initialize the {@link CommonsHttpSolrServer}'s basic parameters.*/private void initialize() {if(responseParser!=null) {server.setParser(responseParser);} else {server.setParser(new XMLResponseParser());}}@SuppressWarnings("unchecked")public void postUpdate() {DBCursor cursor = null;try {for (String c : collectionNames) {LOG.info("MongoDB collection name: " + c);DBCollection collection = MongoHelper.newHelper(mongoConfig).getCollection(c);DBObject q = new BasicDBObject();cursor = collection.find(q);while(cursor.hasNext()) {try {Map<Object, Object> m = cursor.next().toMap();if(manualCommit) {add(m, true);} else {add(m, false);}++totalCount;LOG.info("Add fragment: _id = " + m.get("_id").toString());} catch (IOException e) {e.printStackTrace();}}cursor.close();}LOG.info("Add totalCount: " + totalCount);finallyCommit();optimize(manualOptimize);} catch (MongoException e) {e.printStackTrace();} catch (SolrServerException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/*** Detele lucene {@link Document} by IDs.* @param strings*/public void deleteById(List<String> strings) {try {server.deleteById(strings);} catch (SolrServerException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/*** Detele lucene {@link Document} by query.* @param query*/public void deleteByQuery(String query) {try {server.deleteByQuery(query);} catch (SolrServerException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/*** Query.* @param params* @param fields* @return*/public List<Map<String, Object>> query(SolrParams params, String[] fields) {List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();try {SolrDocumentList documents = server.query(params).getResults();Iterator<SolrDocument> iter = documents.iterator();while(iter.hasNext()) {SolrDocument doc = iter.next();Map<String, Object> map = new HashMap<String, Object>();for(String field : fields) {map.put(field, doc.getFieldValue(field));}results.add(map);}} catch (SolrServerException e) {e.printStackTrace();}return results;}/*** When controlling the committing action at client side, finally execute committing.* @throws SolrServerException* @throws IOException*/private void finallyCommit() throws SolrServerException, IOException {if(!docContainer.isEmpty()) {server.add(docContainer);commit(false, false);}}/*** Commit.* @param waitFlush* @param waitSearcher* @throws SolrServerException* @throws IOException*/public void commit(boolean waitFlush, boolean waitSearcher) {try {server.commit(waitFlush, waitSearcher);} catch (SolrServerException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/*** When controlling the optimizing action at client side, finally execute optimizing.* @param waitFlush* @param waitSearcher* @throws SolrServerException* @throws IOException*/public void optimize(boolean waitFlush, boolean waitSearcher) {try {server.optimize(waitFlush, waitSearcher);commit(waitFlush, waitSearcher);} catch (Exception e) {LOG.error("Encounter error when optimizing.",  e);try {server.rollback();} catch (SolrServerException e1) {e1.printStackTrace();} catch (IOException e1) {e1.printStackTrace();}}}/*** Optimize.* @param optimize* @throws SolrServerException* @throws IOException*/private void optimize(boolean optimize) {if(optimize) {optimize(true, true);}}/*** Add a {@link SolrInputDocument} or collect object and add to the a collection for batch updating* from a mongodb's recored, a Map object.* @param m* @param oneByOne* @throws SolrServerException* @throws IOException*/private void add(Map<Object, Object> m, boolean oneByOne) throws SolrServerException, IOException {SolrInputDocument doc = createDocument(m);if(oneByOne) {server.add(doc);} else {docContainer.add(doc);if(docContainer.size()>maxCommitCount) {server.add(docContainer);server.commit(false, false);docContainer = new ArrayList<SolrInputDocument>();}}}/*** Create a {@link SolrInputDocument} object.* @param record* @return*/private SolrInputDocument createDocument(Map<Object, Object> record) {String id = record.get("_id").toString();String articleId = (String) record.get("articleId");String title = (String) record.get("title");String url = (String) record.get("url");String spiderName = (String) record.get("spiderName");String fragment = makeFragment((BasicDBObject) record.get("fragment"));String word = (String) record.get("word");int pictureCount = (Integer) record.get("pictureCount");int selectedCount = (Integer) record.get("selectedCount");int fragmentSize = (Integer) record.get("fragmentSize");SolrInputDocument doc = new SolrInputDocument();doc.addField("_id", id, 1.0f);doc.addField("articleId", articleId, 1.0f);doc.addField("title", title, 1.0f);doc.addField("url", url, 1.0f);doc.addField("spiderName", spiderName, 1.0f);doc.addField("fragment", fragment, 1.0f);doc.addField("word", word, 1.0f);// Additional processing for lucene payload metadata.doc.addField("pictureCount", word + "|" + pictureCount);doc.addField("coverage", word + "|" + (float)selectedCount/fragmentSize);return doc;}@SuppressWarnings("unchecked")private String makeFragment(BasicDBObject fragment) {StringBuilder builder = new StringBuilder();Iterator<Map.Entry<Integer, String>> iter = fragment.toMap().entrySet().iterator();while(iter.hasNext()) {Map.Entry<Integer, String> entry = iter.next();builder.append(entry.getValue().trim()).append("<br>");}return builder.toString();}/*** Set {@link ResponseParser}, default value is {@link XMLResponseParser}.* @param responseParser*/public void setResponseParser(ResponseParser responseParser) {this.responseParser = responseParser;}/*** Pulling document resource from multiple collections of MongoDB.* @param collectionNames*/public void setCollectionNames(String[] collectionNames) {this.collectionNames = collectionNames;}public void setMaxCommitCount(int maxCommitCount) {this.maxCommitCount = maxCommitCount;}public void setManualCommit(boolean manualCommit) {this.manualCommit = manualCommit;}public void setManualOptimize(boolean manualOptimize) {this.manualOptimize = manualOptimize;}/*** Mongo database configuration.* * @author shirdrn* @date   2011-12-20*/public static class MongoConfig implements Serializable {private static final long serialVersionUID = -3028092758346115702L;private String host;private int port;private String dbname;private String collectionName;public MongoConfig(String host, int port, String dbname, String collectionName) {super();this.host = host;this.port = port;this.dbname = dbname;this.collectionName = collectionName;}@Overridepublic boolean equals(Object obj) {MongoConfig other = (MongoConfig) obj;return host.equals(other.host) && port==other.port&& dbname.equals(other.dbname) && collectionName.equals(other.collectionName);}}/*** Mongo database utility.* * @author shirdrn* @date   2011-12-20*/static class MongoHelper {private static Mongo mongo;private static MongoHelper helper;private MongoConfig mongoConfig;private MongoHelper(MongoConfig mongoConfig) {super();this.mongoConfig = mongoConfig;}public synchronized static MongoHelper newHelper(MongoConfig mongoConfig) {try {if(helper==null) {helper = new MongoHelper(mongoConfig);mongo = new Mongo(mongoConfig.host, mongoConfig.port);Runtime.getRuntime().addShutdownHook(new Thread() {@Overridepublic void run() {if(mongo!=null) {mongo.close();}}});}} catch (Exception e) {e.printStackTrace();}return helper;}			public DBCollection getCollection(String collectionName) {DBCollection c = null;try {c = mongo.getDB(mongoConfig.dbname).getCollection(collectionName);} catch (Exception e) {e.printStackTrace();}return c;}	}
}

下面,我们可以通过写一个测试用例测试一下。

首先,我的Solr搜索服务器已经部署好并启动成功,对应的url为http://192.168.0.197:8080/server/fragment/。测试用例如下所示:

package org.shirdrn.solr.solrj;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import junit.framework.TestCase;import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.request.MapSolrParams;
import org.shirdrn.solr.solrj.SolrPostServer.MongoConfig;@SuppressWarnings("deprecation")
public class TestSolrPostServer extends TestCase {SolrPostServer myServer;MongoConfig config;String url;String[] collectionNames;@Overrideprotected void setUp() throws Exception {url = "http://192.168.0.197:8080/server/fragment/";config = new MongoConfig("192.168.0.184", 27017, "fragment", "");myServer = new SolrPostServer(url, null, config);myServer.setMaxCommitCount(100);}@Overrideprotected void tearDown() throws Exception {super.tearDown();}public void testPostUpdate() {collectionNames = new String[] {"sina","lvping","daodao","go2eu","mafengwo","lotour","17u","sohu","baseSe","bytravel"};myServer.setCollectionNames(collectionNames);myServer.setManualCommit(true);myServer.setManualOptimize(false);myServer.postUpdate();}public void testPostDelete() {List<String> strings = new ArrayList<String>();strings.add("4ef051342c4117a38f63ee97");strings.add("4ef051322c4117a38f63ee36");strings.add("4ef051a42c4117a38f63fb51");strings.add("4ef050d92c4117a38f63dda4");strings.add("4ef051fe2c4117a38f640bc8");strings.add("4ef048ef2c4117a38f6207ce");strings.add("4ef049062c4117a38f620e13");strings.add("4ef046f12c4117a38f6185c0");myServer.deleteById(strings);myServer.commit(false, false);myServer.optimize(true, false);}@SuppressWarnings({ "rawtypes", "unchecked" })public void testQuery() {Map map = new HashMap();map.put(CommonParams.Q, "法国");map.put(CommonParams.START, "0");map.put(CommonParams.ROWS, "10");map.put(CommonParams.FQ, "word:卢浮宫");SolrParams params = new MapSolrParams(map);List<Map<String, Object>> results = myServer.query(params, new String[] {"_id", "title", "url"});assertEquals(10, results.size());}
}

在实际开发的过程中,使用Solrj客户端可以非常容易为测试做一些基本操作,如创建索引,测试Solr基本参数及其开发定制Solr相关接口(Retrieval、Highlighting、Faceted Search、Clustering等等)。


这篇关于使用Solrj管理Solr索引的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/459450

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud