使用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开发一个Ditto剪贴板数据导出工具

《使用Python开发一个Ditto剪贴板数据导出工具》在日常工作中,我们经常需要处理大量的剪贴板数据,下面将介绍如何使用Python的wxPython库开发一个图形化工具,实现从Ditto数据库中读... 目录前言运行结果项目需求分析技术选型核心功能实现1. Ditto数据库结构分析2. 数据库自动定位3

Python yield与yield from的简单使用方式

《Pythonyield与yieldfrom的简单使用方式》生成器通过yield定义,可在处理I/O时暂停执行并返回部分结果,待其他任务完成后继续,yieldfrom用于将一个生成器的值传递给另一... 目录python yield与yield from的使用代码结构总结Python yield与yield

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Oracle查询表结构建表语句索引等方式

《Oracle查询表结构建表语句索引等方式》使用USER_TAB_COLUMNS查询表结构可避免系统隐藏字段(如LISTUSER的CLOB与VARCHAR2同名字段),这些字段可能为dbms_lob.... 目录oracle查询表结构建表语句索引1.用“USER_TAB_COLUMNS”查询表结构2.用“a

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do