Java tutorial
/* * Copyright 2012, TopicQuests * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions * and limitations under the License. */ package org.topicquests.solr; import java.util.*; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.impl.XMLResponseParser; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.client.solrj.response.UpdateResponse; import org.apache.solr.common.SolrInputDocument; //import org.apache.solr.client.solrj.util.ClientUtils; import org.apache.solr.schema.TrieDateField; import org.apache.solr.client.solrj.request.UpdateRequest; import org.topicquests.common.api.IResult; import org.topicquests.common.api.ITopicQuestsOntology; import org.topicquests.common.ResultPojo; import org.topicquests.solr.api.ISolrClient; import org.topicquests.util.LoggingPlatform; //import org.apache.solr.update.DirectUpdateHandler2; /** * @author park * For non-SolrCloud use */ public class Solr3Client implements ISolrClient { private LoggingPlatform log = LoggingPlatform.getLiveInstance(); private HttpSolrServer server; private HttpSolrServer updateServer; private HttpSolrServer harvestServer; @Override public void init(List<String> solrURLs, List<String> zookeeperURL) throws Exception { System.out.println("SERVER3-1 " + solrURLs); String solrURL = null; try { //This is a single server with no zookeeper solrURL = solrURLs.get(0); //NOTE: can pass in a client (String baseURL, HttpClient client) //to which you set params server = new HttpSolrServer(solrURL); } catch (Exception e) { System.out.println("SHIT " + e.getMessage()); } System.out.println("SERVER3-2 " + server); server.getHttpClient().getParams().setParameter("update.chain", "merge"); server.setParser(new XMLResponseParser()); updateServer = new HttpSolrServer(solrURL); updateServer.getHttpClient().getParams().setParameter("update.chain", "partial"); updateServer.setParser(new XMLResponseParser()); harvestServer = new HttpSolrServer(solrURL); harvestServer.getHttpClient().getParams().setParameter("update.chain", "harvest"); harvestServer.setParser(new XMLResponseParser()); System.out.println("SERVER3-3 "); } public SolrServer getSolrServer() { return server; } /** * Run a query based on <code>queryString</code> * @param queryString * @param start TODO * @param count TODO * @return NamedList<Object> in result or error string */ public IResult runQuery(String queryString, int start, int count) { System.out.println("Solr3Client.runQuery- " + queryString + " " + start + " " + count); IResult result = new ResultPojo(); SolrQuery parameters = new SolrQuery(); parameters.set("q", queryString); parameters.setStart(start); if (count > -1) parameters.setRows(count); //force result as JSON // parameters.set("wt", "json"); System.out.println("Solr3Client.runQuery-1 " + parameters.toString()); try { QueryResponse x = server.query(parameters); System.out.println("ZZZZ " + x.getResults()); result.setResultObject(x.getResults()); } catch (Exception e) { log.logError("SolrClient3.runQuery " + e.getMessage() + " " + queryString, e); result.addErrorString(e.getMessage()); } return result; } /** * Update has the effect of removing then replacing a document * @param fields * @return * @deprecated * NOTE: sometimes surgery overwhelms partial update */ public IResult updateData(Map<String, Object> fields) { return addData(fields); } /** * Removes an entire document //TODO needs testing * @param locator * @return */ public IResult deleteByLocator(String locator) { IResult result = new ResultPojo(); try { UpdateResponse ur = server.deleteById(locator); int status = ur.getStatus(); server.commit(); result.setResultObject(new Integer(status)); } catch (Exception e) { result.addErrorString(e.getMessage()); } return result; } /** * Add data based on fields and values in <code>fields</code> * @param fields * @return <code>null</code> or status code as Integer if error with error string * TODO: SolrInputDocument.putAll(Map<String,Object) might work in some cases */ public IResult addData(Map<String, Object> fields) { IResult result = new ResultPojo(); if (fields.isEmpty()) { //result.addErrorString("SolrClient got an empty document"); return result; } log.logDebug("Solr3Client.addData-1 " + fields.size()); int status = 0; try { SolrInputDocument document = mapToDocument(fields); System.out.println("Solr3Client.addData-2 " + document); UpdateResponse response = server.add(document); status = response.getStatus(); //TODO full commit or soft commit? server.commit(); } catch (Exception e) { result.addErrorString(e.getMessage()); log.logError("Solr3Client.addData error-1 " + e.getMessage() + " " + fields, e); } result.setResultObject(new Integer(status)); return result; } @Override public IResult addData(Collection<Map<String, Object>> documents) { IResult result = new ResultPojo(); Iterator<Map<String, Object>> itr = documents.iterator(); int status = 0; try { SolrInputDocument document = null; Map<String, Object> fields = null; List<SolrInputDocument> docs = new ArrayList<SolrInputDocument>(); while (itr.hasNext()) { fields = itr.next(); if (!fields.isEmpty()) { document = mapToDocument(fields); docs.add(document); } //else // result.addErrorString("SolrClient got an empty document"); } UpdateResponse response = server.add(docs); status = response.getStatus(); //TODO full commit or soft commit? server.commit(); } catch (Exception e) { result.addErrorString(e.getMessage()); log.logError("Solr3Client.addData error-2 " + e.getMessage() + " " + documents, e); } result.setResultObject(new Integer(status)); return result; } /** * Fetch by way of the node's <em>locator</em> field * @param locator * @param start * @param count * @return */ public IResult getByProxyLocator(String locator, int start, int count) { String q = ITopicQuestsOntology.LOCATOR_PROPERTY + ":" + locator; System.out.println("QQQ " + q); IResult result = runQuery(q, start, count); return result; } @Override public IResult partialUpdateData(Map<String, Object> fields) { log.logDebug("Solr3Client.partialUpdateData " + fields); return addUpdateData(fields); } @Override public void shutDown() { server.shutdown(); } @Override public IResult addDataNoMerge(Map<String, Object> fields) { IResult result = new ResultPojo(); if (fields.isEmpty()) { //result.addErrorString("SolrClient got an empty document"); return result; } log.logDebug("Solr3Client.addDataNoMerge-1 " + fields.size()); int status = 0; try { SolrInputDocument document = mapToDocument(fields); System.out.println("Solr3Client.addData-2 " + document); UpdateResponse response = harvestServer.add(document); status = response.getStatus(); //TODO full commit or soft commit? server.commit(); } catch (Exception e) { result.addErrorString(e.getMessage()); log.logError("Solr3Client.addDataNoMerge error-1 " + e.getMessage() + " " + fields, e); } result.setResultObject(new Integer(status)); return result; } ///////////////////////////////////// //Support ///////////////////////////////////// /** * <p>Convert a Map of fields to a {@link SolrInputDocument}</p> * <p>Must deal with a variety of field types</p> * @param fields * @return * @throws Exception */ private SolrInputDocument mapToDocument(Map<String, Object> fields) throws Exception { log.logDebug("Solr3Client.mapToDocument- " + fields); SolrInputDocument document = new SolrInputDocument(); Iterator<String> keys = fields.keySet().iterator(); String key; List<String> lobj; Object o; while (keys.hasNext()) { key = keys.next(); o = fields.get(key); System.out.println("Solr3Client.addData-2 " + key + " | " + o); //here we try to catch the obvious ones //TODO expand the test for Float if (key.startsWith(ITopicQuestsOntology.LABEL_PROPERTY) || key.startsWith(ITopicQuestsOntology.DETAILS_PROPERTY)) { if (o instanceof String) document.addField(key, QueryUtil.escapeNodeData((String) o)); else if (o instanceof List) document.addField(key, escapeQueryCulprits((List<String>) o)); else document.addField(key, escapeMapQueryCulprits((Map<String, Object>) o)); } else if (o instanceof String || o instanceof Double || o instanceof Boolean || o instanceof Map || // required for partial updates only o instanceof Long || o instanceof Float) { // System.out.println("Solr3Client.addData-2 "+o); document.addField(key, o); } else if (o instanceof List) { // System.out.println("Solr3Client.addData-2list "+o); lobj = (List<String>) o; Iterator<String> itr = lobj.iterator(); while (itr.hasNext()) { //TODO if the list is just a list of single strings, e.g. mostly locators, //then we don't want to escape them //document.addField(key, ClientUtils.escapeQueryChars(vx)); //document.addField(key, escapeQueryCulprits(vx)); //unit tests suggest we don't need to do any escapes //TODO pay attention to this issue document.addField(key, itr.next()); } } else if (key.equals(ITopicQuestsOntology.CREATED_DATE_PROPERTY) || key.equals(ITopicQuestsOntology.LAST_EDIT_DATE_PROPERTY)) { document.addField(key, TrieDateField.formatExternal((Date) o)); } else throw new Exception("Solr3Client.addData fail: " + key + " " + o); } return document; } private Map<String, Object> escapeMapQueryCulprits(Map<String, Object> m) { Map<String, Object> result = m; Object obj; Map<String, Object> mx; List<String> vx; String key; String vs; Iterator<String> itr = m.keySet().iterator(); while (itr.hasNext()) { key = itr.next(); obj = m.get(key); if (obj instanceof List) { vx = escapeQueryCulprits((List<String>) obj); result.put(key, vx); } else if (obj instanceof String) { vs = QueryUtil.escapeNodeData((String) obj); result.put(key, vs); } } return result; } private List<String> escapeQueryCulprits(List<String> culprits) { int len = culprits.size(); for (int i = 0; i < len; i++) { culprits.set(i, QueryUtil.escapeNodeData(culprits.get(i))); } return culprits; } /////////////////////////////////////////////// // Partial updates use their own kind of map // { // locator=<thelocator>, // fieldA={set=[values]}, // fieldB={set=[<values>]}, // fieldC={set=[values]} private IResult addUpdateData(Map<String, Object> fields) { IResult result = new ResultPojo(); if (fields.isEmpty()) { //result.addErrorString("SolrClient got an empty document"); return result; } log.logDebug("Solr3Client.addUpdateData-1 " + fields.size()); int status = 0; try { SolrInputDocument document = mapToDocument(fields); //updateMapToDocument(fields); log.logDebug("Solr3Client.addUpdateData-2 " + document); UpdateRequest ur = new UpdateRequest(); ur.add(document); ur.setCommitWithin(1000); UpdateResponse response = ur.process(updateServer); status = response.getStatus(); //TODO full commit or soft commit? //server.commit(); } catch (Exception e) { result.addErrorString(e.getMessage()); log.logError("Solr3Client.addUpdateData error-1 " + e.getMessage() + " " + fields, e); } result.setResultObject(new Integer(status)); return result; } /** apparently not used private SolrInputDocument updateMapToDocument(Map<String,Object> updateFields) { log.logDebug("Solr3Client.updateMapToDocument- "+updateFields); SolrInputDocument document = new SolrInputDocument(); String key; Object obj; Map<String,Object>mobj; Map<String,Object>internalM; Iterator<String>itr = updateFields.keySet().iterator(); Iterator<String>fitr; String field; List<String>fx; Iterator<String>iitr; String internalKey; while (itr.hasNext()) { key = itr.next(); obj = updateFields.get(key); if (key.equals(ITopicQuestsOntology.LOCATOR_PROPERTY)) document.addField(key, obj); else { if (obj instanceof Map) { mobj = (Map<String,Object>)obj; fitr = mobj.keySet().iterator(); while (fitr.hasNext()) { field = fitr.next(); obj = mobj.get(field); if (obj instanceof Map) { internalM = (Map<String,Object>)obj; if (field.startsWith(ITopicQuestsOntology.LABEL_PROPERTY) || field.startsWith(ITopicQuestsOntology.DETAILS_PROPERTY)) { iitr = internalM.keySet().iterator(); while (iitr.hasNext()) { internalKey = iitr.next(); obj = internalM.get(internalKey); if (obj instanceof List) { fx = this.escapeQueryCulprits((List<String>)obj); internalM.put(internalKey, fx); document.addField(key,internalM); } else { document.addField(key, QueryUtil.escapeNodeData((String)obj)); } } } //TODO What about updated dates? //else if (field.startsWith(ITopicQuestsOntology.CREATED_DATE_PROPERTY) || // field.startsWith(ITopicQuestsOntology.LAST_EDIT_DATE_PROPERTY)) { //document.addField(key, TrieDateField.formatExternal((Date)o)); // } } else { document.addField(key, obj); } } } } } return document; } */ }