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

相关文章

Spring IoC 容器的使用详解(最新整理)

《SpringIoC容器的使用详解(最新整理)》文章介绍了Spring框架中的应用分层思想与IoC容器原理,通过分层解耦业务逻辑、数据访问等模块,IoC容器利用@Component注解管理Bean... 目录1. 应用分层2. IoC 的介绍3. IoC 容器的使用3.1. bean 的存储3.2. 方法注

Python内置函数之classmethod函数使用详解

《Python内置函数之classmethod函数使用详解》:本文主要介绍Python内置函数之classmethod函数使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 类方法定义与基本语法2. 类方法 vs 实例方法 vs 静态方法3. 核心特性与用法(1编程客

Linux中压缩、网络传输与系统监控工具的使用完整指南

《Linux中压缩、网络传输与系统监控工具的使用完整指南》在Linux系统管理中,压缩与传输工具是数据备份和远程协作的桥梁,而系统监控工具则是保障服务器稳定运行的眼睛,下面小编就来和大家详细介绍一下它... 目录引言一、压缩与解压:数据存储与传输的优化核心1. zip/unzip:通用压缩格式的便捷操作2.

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

MySQL之InnoDB存储引擎中的索引用法及说明

《MySQL之InnoDB存储引擎中的索引用法及说明》:本文主要介绍MySQL之InnoDB存储引擎中的索引用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录1、背景2、准备3、正篇【1】存储用户记录的数据页【2】存储目录项记录的数据页【3】聚簇索引【4】二

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

Spring 框架之Springfox使用详解

《Spring框架之Springfox使用详解》Springfox是Spring框架的API文档工具,集成Swagger规范,自动生成文档并支持多语言/版本,模块化设计便于扩展,但存在版本兼容性、性... 目录核心功能工作原理模块化设计使用示例注意事项优缺点优点缺点总结适用场景建议总结Springfox 是

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、