使用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

相关文章

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

MyBatis ParameterHandler的具体使用

《MyBatisParameterHandler的具体使用》本文主要介绍了MyBatisParameterHandler的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、概述二、源码1 关键属性2.setParameters3.TypeHandler1.TypeHa