001/* 002 * File : $Source$ 003 * Date : $Date$ 004 * Version: $Revision$ 005 * 006 * This library is part of OpenCms - 007 * the Open Source Content Management System 008 * 009 * Copyright (C) 2002 - 2009 Alkacon Software (http://www.alkacon.com) 010 * 011 * This library is free software; you can redistribute it and/or 012 * modify it under the terms of the GNU Lesser General Public 013 * License as published by the Free Software Foundation; either 014 * version 2.1 of the License, or (at your option) any later version. 015 * 016 * This library is distributed in the hope that it will be useful, 017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 * Lesser General Public License for more details. 020 * 021 * For further information about Alkacon Software, please see the 022 * company website: http://www.alkacon.com 023 * 024 * For further information about OpenCms, please see the 025 * project website: http://www.opencms.org 026 * 027 * You should have received a copy of the GNU Lesser General Public 028 * License along with this library; if not, write to the Free Software 029 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 030 */ 031 032package org.opencms.search.solr; 033 034import org.opencms.db.CmsPublishedResource; 035import org.opencms.main.CmsLog; 036import org.opencms.main.OpenCms; 037import org.opencms.search.I_CmsSearchDocument; 038import org.opencms.search.fields.CmsSearchField; 039 040import java.io.IOException; 041import java.util.List; 042 043import org.apache.commons.logging.Log; 044import org.apache.solr.client.solrj.SolrClient; 045import org.apache.solr.client.solrj.SolrServerException; 046import org.apache.solr.common.SolrException; 047import org.apache.solr.common.SolrInputDocument; 048 049/** 050 * Implements the index writer for the Solr server used by OpenCms.<p> 051 * 052 * @since 8.5.0 053 */ 054public class CmsSolrIndexWriter implements I_CmsSolrIndexWriter { 055 056 /** The log object for this class. */ 057 protected static final Log LOG = CmsLog.getLog(CmsSolrIndexWriter.class); 058 059 /** The time to wait before a commit is sent to the Solr index. */ 060 private int m_commitMs = new Long( 061 OpenCms.getSearchManager().getSolrServerConfiguration().getSolrCommitMs()).intValue(); 062 063 /** The Solr index. */ 064 private CmsSolrIndex m_index; 065 066 /** The Solr client. */ 067 private SolrClient m_server; 068 069 /** 070 * Constructor to create a Solr index writer.<p> 071 * 072 * @param client the client to use 073 */ 074 public CmsSolrIndexWriter(SolrClient client) { 075 076 this(client, null); 077 } 078 079 /** 080 * Creates a new index writer based on the provided standard Lucene IndexWriter for the 081 * provided OpenCms search index instance.<p> 082 * 083 * The OpenCms search instance is currently used only for improved logging of the 084 * index operations.<p> 085 * 086 * @param client the standard Lucene IndexWriter to use as delegate 087 * @param index the OpenCms search index instance this writer to supposed to write to 088 */ 089 public CmsSolrIndexWriter(SolrClient client, CmsSolrIndex index) { 090 091 m_index = index; 092 m_server = client; 093 if (m_index != null) { 094 LOG.info( 095 Messages.get().getBundle().key( 096 Messages.LOG_SOLR_WRITER_CREATE_2, 097 m_index.getName(), 098 m_index.getPath())); 099 } 100 } 101 102 /** 103 * @see org.opencms.search.I_CmsIndexWriter#close() 104 */ 105 public void close() { 106 107 // nothing to do here 108 } 109 110 /** 111 * @see org.opencms.search.I_CmsIndexWriter#commit() 112 */ 113 public void commit() throws IOException { 114 115 if ((m_server != null) && (m_index != null)) { 116 try { 117 LOG.info( 118 Messages.get().getBundle().key( 119 Messages.LOG_SOLR_WRITER_COMMIT_2, 120 m_index.getName(), 121 m_index.getPath())); 122 m_server.commit(); 123 } catch (SolrServerException e) { 124 throw new IOException(e.getLocalizedMessage(), e); 125 } 126 } 127 } 128 129 /** 130 * @see org.opencms.search.solr.I_CmsSolrIndexWriter#deleteAllDocuments() 131 */ 132 public void deleteAllDocuments() throws IOException { 133 134 if ((m_server != null) && (m_index != null)) { 135 try { 136 LOG.info( 137 Messages.get().getBundle().key( 138 Messages.LOG_SOLR_WRITER_DELETE_ALL_2, 139 m_index.getName(), 140 m_index.getPath())); 141 m_server.deleteByQuery("*:*", m_commitMs); 142 } catch (SolrServerException e) { 143 throw new IOException(e.getLocalizedMessage(), e); 144 } 145 } 146 } 147 148 /** 149 * @see org.opencms.search.I_CmsIndexWriter#deleteDocument(org.opencms.db.CmsPublishedResource) 150 */ 151 public void deleteDocument(CmsPublishedResource resource) throws IOException { 152 153 if ((m_server != null) && (m_index != null)) { 154 try { 155 LOG.info( 156 Messages.get().getBundle().key( 157 Messages.LOG_SOLR_WRITER_DOC_DELETE_3, 158 resource.getRootPath(), 159 m_index.getName(), 160 m_index.getPath())); 161 m_server.deleteByQuery("id:" + resource.getStructureId().toString(), m_commitMs); 162 } catch (SolrServerException e) { 163 throw new IOException(e.getLocalizedMessage(), e); 164 } catch (SolrException e) { 165 throw new IOException(e.getLocalizedMessage(), e); 166 } 167 } 168 } 169 170 /** 171 * @see org.opencms.search.I_CmsIndexWriter#optimize() 172 */ 173 public void optimize() { 174 175 // optimization is not recommended 176 // should be configured within solrconfig.xml 177 } 178 179 /** 180 * @see org.opencms.search.I_CmsIndexWriter#updateDocument(java.lang.String, org.opencms.search.I_CmsSearchDocument) 181 */ 182 public void updateDocument(String rootPath, I_CmsSearchDocument document) throws IOException { 183 184 if ((m_server != null) && (m_index != null)) { 185 186 if (document.getDocument() != null) { 187 try { 188 m_server.deleteByQuery("path:\"" + rootPath + "\"", m_commitMs); 189 } catch (Exception e1) { 190 LOG.error(e1.getLocalizedMessage(), e1); 191 } 192 try { 193 LOG.info( 194 Messages.get().getBundle().key( 195 Messages.LOG_SOLR_WRITER_DOC_UPDATE_3, 196 rootPath, 197 m_index.getName(), 198 m_index.getPath())); 199 addDocumentInstances(document); 200 } catch (SolrServerException e) { 201 throw new IOException(e.getLocalizedMessage(), e); 202 } 203 } 204 } 205 } 206 207 /** 208 * Adds Solr documents to the index for the {@link I_CmsSearchDocument}. 209 * Documents for serial dates are added for each occurrence once with the date of the respective occurrence. 210 * @param document the document for the indexed resource 211 * @throws SolrServerException thrown if adding the document to the index fails 212 * @throws IOException thrown if adding the document to the index fails 213 */ 214 private void addDocumentInstances(I_CmsSearchDocument document) throws SolrServerException, IOException { 215 216 List<String> serialDates = document.getMultivaluedFieldAsStringList(CmsSearchField.FIELD_SERIESDATES); 217 SolrInputDocument inputDoc = (SolrInputDocument)document.getDocument(); 218 String id = inputDoc.getFieldValue(CmsSearchField.FIELD_ID).toString(); 219 if (null != serialDates) { 220 // NOTE: We can assume the following to arrays have the same length as serialDates. 221 List<String> serialDatesEnd = document.getMultivaluedFieldAsStringList( 222 CmsSearchField.FIELD_SERIESDATES_END); 223 List<String> serialDatesCurrentTill = document.getMultivaluedFieldAsStringList( 224 CmsSearchField.FIELD_SERIESDATES_CURRENT_TILL); 225 for (int i = 0; i < serialDates.size(); i++) { 226 String date = serialDates.get(i); 227 String endDate = serialDatesEnd.get(i); 228 String currentTillDate = serialDatesCurrentTill.get(i); 229 inputDoc.setField(CmsSearchField.FIELD_INSTANCEDATE + CmsSearchField.FIELD_POSTFIX_DATE, date); 230 inputDoc.setField(CmsSearchField.FIELD_INSTANCEDATE_END + CmsSearchField.FIELD_POSTFIX_DATE, endDate); 231 inputDoc.setField( 232 CmsSearchField.FIELD_INSTANCEDATE_CURRENT_TILL + CmsSearchField.FIELD_POSTFIX_DATE, 233 currentTillDate); 234 for (String locale : document.getMultivaluedFieldAsStringList(CmsSearchField.FIELD_CONTENT_LOCALES)) { 235 inputDoc.setField( 236 CmsSearchField.FIELD_INSTANCEDATE + "_" + locale + CmsSearchField.FIELD_POSTFIX_DATE, 237 date); 238 inputDoc.setField( 239 CmsSearchField.FIELD_INSTANCEDATE_END + "_" + locale + CmsSearchField.FIELD_POSTFIX_DATE, 240 endDate); 241 inputDoc.setField( 242 CmsSearchField.FIELD_INSTANCEDATE_CURRENT_TILL 243 + "_" 244 + locale 245 + CmsSearchField.FIELD_POSTFIX_DATE, 246 currentTillDate); 247 } 248 String newId = id + String.format("-%04d", Integer.valueOf(i + 1)); 249 inputDoc.setField(CmsSearchField.FIELD_SOLR_ID, newId); 250 //remove fields that should not be part of the index, but were used to transport extra-information on date series 251 inputDoc.removeField(CmsSearchField.FIELD_SERIESDATES_END); 252 inputDoc.removeField(CmsSearchField.FIELD_SERIESDATES_CURRENT_TILL); 253 m_server.add(inputDoc, m_commitMs); 254 } 255 } else { 256 inputDoc.setField(CmsSearchField.FIELD_SOLR_ID, id); 257 m_server.add(inputDoc, m_commitMs); 258 } 259 260 } 261}