/***************************************************************************** * * Copyright (C) Zenoss, Inc. 2010, 2014, all rights reserved. * * This content is made available according to terms specified in * License.zenoss under the directory where your Zenoss product is installed. * ****************************************************************************/ package org.zenoss.zep.index.impl.solr; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrQuery.ORDER; import org.apache.solr.client.solrj.SolrQuery.SortClause; import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.StreamingResponseCallback; import org.apache.solr.client.solrj.impl.CloudSolrServer; import org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrServer; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.response.CollectionAdminResponse; import org.apache.solr.client.solrj.response.PivotField; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.params.CoreAdminParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.TaskScheduler; import org.zenoss.protobufs.zep.Zep.*; import org.zenoss.protobufs.zep.Zep.EventSort.Field; import org.zenoss.zep.Messages; import org.zenoss.zep.UUIDGenerator; import org.zenoss.zep.ZepException; import org.zenoss.zep.dao.EventArchiveDao; import org.zenoss.zep.index.IndexedDetailsConfiguration; import org.zenoss.zep.index.SavedSearchProcessor; import org.zenoss.zep.index.impl.BaseEventIndexBackend; import org.zenoss.zep.index.impl.IndexConstants; import org.zenoss.zep.utils.AtomicThresholdCounter; import java.io.IOException; import java.util.*; import java.util.concurrent.TimeUnit; import static org.zenoss.zep.index.impl.IndexConstants.*; import static org.zenoss.zep.index.impl.IndexConstants.FIELD_EVENT_GROUP; public class SolrEventIndexBackend extends BaseEventIndexBackend<SolrSavedSearch> { public static final int MAX_RESULTS = 100; private static Logger logger = LoggerFactory.getLogger(SolrEventIndexBackend.class); private static final Map<Field, String> SORT_MAP; static { Map<Field, String> m = Maps.newEnumMap(Field.class); m.put(Field.COUNT, FIELD_COUNT); m.put(Field.ELEMENT_IDENTIFIER, FIELD_ELEMENT_IDENTIFIER_NOT_ANALYZED); m.put(Field.ELEMENT_SUB_IDENTIFIER, FIELD_ELEMENT_SUB_IDENTIFIER_NOT_ANALYZED); m.put(Field.ELEMENT_TITLE, FIELD_ELEMENT_TITLE_NOT_ANALYZED); m.put(Field.ELEMENT_SUB_TITLE, FIELD_ELEMENT_SUB_TITLE_NOT_ANALYZED); m.put(Field.EVENT_CLASS, FIELD_EVENT_CLASS_NOT_ANALYZED); m.put(Field.EVENT_SUMMARY, FIELD_SUMMARY_NOT_ANALYZED); m.put(Field.FIRST_SEEN, FIELD_FIRST_SEEN_TIME); m.put(Field.LAST_SEEN, FIELD_LAST_SEEN_TIME); m.put(Field.SEVERITY, FIELD_SEVERITY); m.put(Field.STATUS, FIELD_STATUS); m.put(Field.STATUS_CHANGE, FIELD_STATUS_CHANGE_TIME); m.put(Field.UPDATE_TIME, FIELD_UPDATE_TIME); m.put(Field.CURRENT_USER_NAME, FIELD_CURRENT_USER_NAME); m.put(Field.AGENT, FIELD_AGENT); m.put(Field.MONITOR, FIELD_MONITOR); m.put(Field.EVENT_KEY, FIELD_EVENT_KEY); m.put(Field.UUID, FIELD_UUID); m.put(Field.FINGERPRINT, FIELD_FINGERPRINT); m.put(Field.EVENT_CLASS_KEY, FIELD_EVENT_CLASS_KEY); m.put(Field.EVENT_GROUP, FIELD_EVENT_GROUP); SORT_MAP = Collections.unmodifiableMap(m); } public final String name; private boolean ready = false; private int optimizeThreshold = -1; // disabled, for now. private OptimizeThread optimizeThread = null; private final AtomicThresholdCounter eventsSinceOptimize = new AtomicThresholdCounter(0); private final EventArchiveDao archiveDao; private final IndexedDetailsConfiguration indexedDetailsConfiguration; private final SolrServer queryServer; private final int shards; private final int replicationFactor; private final int maxShardsPerNode; private final int concurrentUploadQueueSize; private final int concurrentThreads; private SolrServer updateServer; public SolrEventIndexBackend(String name, String server, IndexedDetailsConfiguration indexedDetailsConfiguration, EventArchiveDao archiveDao, int shards, int replicationFactor, int maxShardsPerNode, int concurrentUploadQueueSize, int concurrentThreads, Messages messages, TaskScheduler scheduler, UUIDGenerator uuidGenerator, int tagSeverityCacheSize, int tagSeveritiesCacheTTL) { super(messages, scheduler, uuidGenerator, tagSeverityCacheSize, tagSeveritiesCacheTTL); this.name = name; this.indexedDetailsConfiguration = indexedDetailsConfiguration; this.archiveDao = archiveDao; this.shards = shards; this.replicationFactor = replicationFactor; this.maxShardsPerNode = maxShardsPerNode; this.concurrentUploadQueueSize = concurrentUploadQueueSize; this.concurrentThreads = concurrentThreads; if (server.toLowerCase().startsWith("http://") || server.toLowerCase().startsWith("https://")) { this.queryServer = new HttpSolrServer(server); } else { CloudSolrServer cloudServer = new CloudSolrServer(server); cloudServer.setIdField("uuid"); this.updateServer = this.queryServer = cloudServer; } } public static class CollectionListAdminRequest extends CollectionAdminRequest { @Override public SolrParams getParams() { ModifiableSolrParams params = new ModifiableSolrParams(); params.set(CoreAdminParams.ACTION, "LIST"); return params; } } public synchronized boolean initializeSolr() { try { CollectionAdminResponse response = new CollectionListAdminRequest().process(queryServer); Set<String> collections = Sets.newHashSet((Collection<String>) response.getResponse().get("collections")); if (!collections.contains(name)) { response = CollectionAdminRequest.createCollection(name, shards, replicationFactor, maxShardsPerNode, null, "zenoss_events", "uuid", queryServer); if (!response.isSuccess()) { logger.error("Failed to initialize Solr: " + response.toString()); return false; } } if (queryServer instanceof HttpSolrServer) { String baseUrl = ((HttpSolrServer) queryServer).getBaseURL(); String newBaseUrl = baseUrl.matches("/zenoss_events/?$") ? baseUrl : baseUrl.replaceAll("/*$", "/zenoss_events/"); ((HttpSolrServer) queryServer).setBaseURL(baseUrl.replaceAll("/*$", "/zenoss_events/")); updateServer = new ConcurrentUpdateSolrServer(newBaseUrl, concurrentUploadQueueSize, concurrentThreads); } else if (queryServer instanceof CloudSolrServer) { ((CloudSolrServer) queryServer).setDefaultCollection("zenoss_events"); } this.ready = true; return true; } catch (SolrException e) { logger.error("Failed to initialize Solr: " + e.getMessage(), e); return false; } catch (SolrServerException e) { logger.error("Failed to initialize Solr: " + e.getMessage(), e); return false; } catch (IOException e) { logger.error("Failed to initialize Solr: " + e.getMessage(), e); return false; } } private class OptimizeThread extends Thread { private volatile boolean shutdown = false; public OptimizeThread() { setName(SolrEventIndexBackend.class.getName() + " optimize thread"); setPriority(Math.min(Thread.currentThread().getPriority() + 2, Thread.MAX_PRIORITY)); setDaemon(true); } public void run() { boolean interrupted = false; try { while (!shutdown) { try { final int threshold = optimizeThreshold; if (threshold <= 0 || !ready) Thread.sleep(100); else if (eventsSinceOptimize.awaitAndReset(threshold, 100, TimeUnit.MILLISECONDS)) queryServer.optimize(); } catch (InterruptedException e) { interrupted = true; } catch (IOException e) { logger.warn("exception while optimizing: " + e.getMessage(), e); } catch (SolrServerException e) { logger.warn("exception while optimizing: " + e.getMessage(), e); } } } finally { if (interrupted) { Thread.currentThread().interrupt(); } } } public boolean isDown() { return shutdown || !this.isAlive(); } public void close() { shutdown = true; } } private synchronized void startOptimizeThread() { stopOptimizeThread(); if (optimizeThreshold > 0) { logger.debug("Starting %s optimize thread", getClass().getName()); optimizeThread = new OptimizeThread(); optimizeThread.start(); } } private synchronized void stopOptimizeThread() { if (optimizeThread != null) { if (optimizeThread.isAlive()) { logger.debug("Stopping %s optimize thread", getClass().getName()); optimizeThread.close(); } optimizeThread = null; } } public synchronized void setOptimizeThreshold(final int threshold) { final int old = optimizeThreshold; if (old != threshold) { optimizeThreshold = threshold; if (threshold <= 0) stopOptimizeThread(); else if (old <= 0 || optimizeThread == null || optimizeThread.isDown()) startOptimizeThread(); } } private class SolrInitializationThread extends Thread { @Override public void run() { try { while (!initializeSolr()) { logger.info("Could not initialize solr backend."); //TODO implement exponential backoff or something more sophisticated sleep(1000); } logger.info("Solr Indexing enabled"); startOptimizeThread(); } catch (InterruptedException e) { // ignore it } } } public synchronized boolean start() { SolrInitializationThread initThread = new SolrInitializationThread(); initThread.start(); return this.ready; } public synchronized void shutdown() { stopOptimizeThread(); this.queryServer.shutdown(); if (this.updateServer != null) this.updateServer.shutdown(); } @Override public boolean isReady() { return ready; } @Override public boolean ping() { boolean pingable = false; if (ready) { try { this.queryServer.ping(); pingable = true; } catch (SolrServerException e) { logger.debug(e.getMessage(), e); } catch (SolrException e) { logger.debug(e.getMessage(), e); } catch (IOException e) { logger.debug(e.getMessage(), e); } } return pingable; } private void assertReady() { if (!ready) throw new IllegalStateException("Solr failed to initialize"); } private boolean checkReady() { if (!ready && logger.isDebugEnabled()) logger.debug("Request ignored. Solr failed to initialize."); return ready; } @Override public long count() throws ZepException { assertReady(); try { SolrQuery query = new SolrQuery().setQuery("*:*").setRows(0); return queryServer.query(query).getResults().getNumFound(); } catch (SolrServerException e) { throw new ZepException(e); } } @Override public long sizeInBytes() throws UnsupportedOperationException { assertReady(); throw new UnsupportedOperationException(); } @Override public void index(EventSummary event) throws ZepException { if (!checkReady()) return; SolrInputDocument doc = SolrEventIndexMapper.fromEventSummary(event, indexedDetailsConfiguration.getEventDetailItemsByName()); logger.debug("Indexing {}", event.getUuid()); try { updateServer.add(doc); eventsSinceOptimize.increment(); } catch (IOException e) { throw new ZepException(e); } catch (SolrServerException e) { throw new ZepException(e); } catch (SolrException e) { throw new ZepException(e); } } @Override public void index(Collection<EventSummary> events) throws ZepException { if (!checkReady()) return; List<SolrInputDocument> docs = Lists.newArrayListWithExpectedSize(events.size()); for (EventSummary event : events) { docs.add(SolrEventIndexMapper.fromEventSummary(event, indexedDetailsConfiguration.getEventDetailItemsByName())); } try { updateServer.add(docs); eventsSinceOptimize.increment(docs.size()); } catch (SolrException e) { throw new ZepException(e); } catch (SolrServerException e) { throw new ZepException(e); } catch (IOException e) { throw new ZepException(e); } } @Override public void delete(String eventUuid) throws ZepException { if (!checkReady()) return; try { updateServer.deleteById(eventUuid); eventsSinceOptimize.increment(); } catch (SolrServerException e) { throw new ZepException(e); } catch (IOException e) { throw new ZepException(e); } } @Override public void delete(Collection<String> eventUuids) throws ZepException { if (!checkReady()) return; try { if (eventUuids instanceof List) { updateServer.deleteById((List<String>)eventUuids); } else { updateServer.deleteById(Lists.newArrayList(eventUuids)); } eventsSinceOptimize.increment(eventUuids.size()); } catch (SolrServerException e) { throw new ZepException(e); } catch (IOException e) { throw new ZepException(e); } } @Override public void flush() throws ZepException { if (!checkReady()) return; try { updateServer.commit(true, true, true); } catch (SolrServerException e) { throw new ZepException(e); } catch (IOException e) { throw new ZepException(e); } } @Override public void purge(Date threshold) throws ZepException { if (!checkReady()) return; SolrQueryBuilder query = new SolrQueryBuilder(indexedDetailsConfiguration); query.addRange(IndexConstants.FIELD_LAST_SEEN_TIME, null, threshold.getTime()); logger.info("Purging events older than {}", threshold); logger.debug("Solr query: {}", query); try { updateServer.deleteByQuery(query.build()); eventsSinceOptimize.incrementTo(optimizeThreshold); } catch (SolrServerException e) { throw new ZepException(e); } catch (IOException e) { throw new ZepException(e); } } @Override public void clear() throws ZepException { if (!checkReady()) return; try { updateServer.deleteByQuery("*:*"); flush(); eventsSinceOptimize.incrementTo(optimizeThreshold); } catch (SolrServerException e) { throw new ZepException(e); } catch (IOException e) { throw new ZepException(e); } } @Override public EventSummaryResult list(EventSummaryRequest request) throws ZepException { assertReady(); List<EventSort> sorts = request.getSortCount() == 0 ? Collections.<EventSort>emptyList() : request.getSortList(); SolrQuery solrQuery = buildSolrQuery(request.getEventFilter(), request.getExclusionFilter(), request.hasLimit() ? request.getLimit() : null, request.hasOffset() ? request.getOffset() : null, sorts, SolrFieldFilter.UUID_LAST_SEEN_AND_PROTOBUF); return execute(solrQuery, false); } @Override public EventSummaryResult listUuids(EventSummaryRequest request) throws ZepException { assertReady(); List<EventSort> sorts = request.getSortCount() == 0 ? Collections.<EventSort>emptyList() : request.getSortList(); SolrQuery solrQuery = buildSolrQuery(request.getEventFilter(), request.getExclusionFilter(), request.hasLimit() ? request.getLimit() : null, request.hasOffset() ? request.getOffset() : null, sorts, SolrFieldFilter.JUST_UUID); return execute(solrQuery, true); } private EventSummaryResult execute(final SolrQuery query, boolean justUuids) throws ZepException { EventSummaryResult.Builder result = EventSummaryResult.newBuilder(); logger.debug("Searching SOLR for events matching: {}", query.getQuery()); final long now = logger.isDebugEnabled() ? System.currentTimeMillis() : 0; final QueryResponse response; try { response = queryServer.query(query); final int numFound = (int) response.getResults().getNumFound(); result.setTotal(numFound); if (query.getRows() != null) { final int limit = query.getRows(); final int offset = (query.getStart() == null) ? 0 : query.getStart() ; result.setLimit(limit); if (numFound > offset + limit) result.setNextOffset(offset + limit); } logger.debug("Found {} results in SOLR", numFound); if (justUuids) { for (SolrDocument doc : response.getResults()) result.addEvents(SolrEventIndexMapper.toEventSummary(doc)); } else { Map<String, EventSummary> sortedResults = Maps.newLinkedHashMap(); Set<EventSummary> toLookup = Sets.newHashSet(); for (SolrDocument doc : response.getResults()) { EventSummary event = SolrEventIndexMapper.toEventSummary(doc); if (event.hasFirstSeenTime()) { sortedResults.put(event.getUuid(), event); } else { // We only store keys in the index for archived events. This must be one of those. // Set a place-holder now. We'll find it in the database shortly. sortedResults.put(event.getUuid(), null); toLookup.add(event); } } if (!toLookup.isEmpty()) { final long beforeLookup = System.currentTimeMillis(); logger.debug("Looking up {} events by UUID", toLookup.size()); List<EventSummary> events = archiveDao.findByKey(toLookup); if (events.size() != toLookup.size()) { int missing = toLookup.size() - events.size(); logger.info("Event archive index out of sync - {} of {} event UUIDs are in Solr index, but not in database.", missing, toLookup.size()); } for (EventSummary event : events) sortedResults.put(event.getUuid(), event); // a re-insertion -- solr sort is preserved. logger.debug("Query spent {} milliseconds to lookup {} events by UUID.", System.currentTimeMillis() - beforeLookup, toLookup.size()); } else { logger.debug("Query did not have to lookup any events by UUID"); } for (EventSummary event : sortedResults.values()) if (event != null) result.addEvents(event); } } catch (SolrServerException e) { throw new ZepException(e); } finally { if (logger.isDebugEnabled()) logger.debug("Query {} finished in {} milliseconds", query, System.currentTimeMillis() - now); } return result.build(); } @Override public EventSummary findByUuid(String uuid) throws ZepException { assertReady(); SolrQuery solrQuery = new SolrQuery(). setQuery(IndexConstants.FIELD_UUID + ':' + uuid). setFields(IndexConstants.FIELD_UUID, IndexConstants.FIELD_PROTOBUF). setRows(1); SolrDocumentList docs; try { QueryResponse response = queryServer.query(solrQuery); docs = response.getResults(); } catch (SolrServerException e) { throw new ZepException(e); } if ( docs.size() > 0) { return SolrEventIndexMapper.toEventSummary(docs.get(0)); } else { return null; } } @Override public SavedSearchProcessor<SolrSavedSearch> savedSearchProcessor() { assertReady(); return new SavedSearchProcessor<SolrSavedSearch>(){ @Override public EventSummaryResult result(SolrSavedSearch search, int offset, int limit) throws ZepException { SolrQuery query = search.getSolrQuery().getCopy(); query.setRows(limit); query.setStart(offset); query.setFields(IndexConstants.FIELD_UUID, IndexConstants.FIELD_LAST_SEEN_TIME, IndexConstants.FIELD_PROTOBUF); return execute(query, false); } }; } @Override public SavedSearchProcessor<SolrSavedSearch> savedSearchUuidsProcessor() { assertReady(); return new SavedSearchProcessor<SolrSavedSearch>() { @Override public EventSummaryResult result(SolrSavedSearch search, int offset, int limit) throws ZepException { SolrQuery query = search.getSolrQuery().getCopy(); query.setRows(limit); query.setStart(offset); query.setFields(IndexConstants.FIELD_UUID, IndexConstants.FIELD_LAST_SEEN_TIME); return execute(query, true); } }; } @Override public SolrSavedSearch buildSavedSearch(String uuid, EventQuery query) throws ZepException { assertReady(); List<EventSort> sorts = query.getSortCount() == 0 ? Collections.<EventSort>emptyList() : query.getSortList(); SolrQuery solrQuery = buildSolrQuery(query.getEventFilter(), query.getExclusionFilter(), null, null, sorts, null); return new SolrSavedSearch(uuid, query.getTimeout(), solrQuery); } private SolrQuery buildSolrQuery(EventFilter filter, EventFilter exclusionFilter, Integer limit, Integer offset, List<EventSort> sortList, SolrFieldFilter fieldFilter) throws ZepException { final String query = buildQuery(filter, exclusionFilter); SolrQuery solrQuery = new SolrQuery().setQuery(query); if (limit != null && limit < MAX_RESULTS && limit > 0) solrQuery.setRows(limit); else solrQuery.setRows(MAX_RESULTS); if (offset != null) solrQuery.setStart(offset); if (sortList == null) solrQuery.clearSorts(); else if (sortList.isEmpty()) solrQuery.addSort(SortClause.desc(IndexConstants.FIELD_LAST_SEEN_TIME)); else for (EventSort sort : sortList) for (SortClause clause : createSortClauses(sort)) solrQuery.addSort(clause); if (fieldFilter != null) { switch (fieldFilter) { case DEFAULTS: break; case JUST_UUID: solrQuery.setFields(IndexConstants.FIELD_UUID); break; case UUID_LAST_SEEN_AND_PROTOBUF: solrQuery.setFields( IndexConstants.FIELD_UUID, IndexConstants.FIELD_LAST_SEEN_TIME, IndexConstants.FIELD_PROTOBUF); break; case SEARCH_EVENT_TAG_SEVERITIES: solrQuery.setFields( IndexConstants.FIELD_ELEMENT_IDENTIFIER, IndexConstants.FIELD_ELEMENT_SUB_IDENTIFIER, IndexConstants.FIELD_SEVERITY, IndexConstants.FIELD_STATUS, IndexConstants.FIELD_TAGS, IndexConstants.FIELD_COUNT); break; default: throw new IllegalStateException("Unexpected fieldFilter: " + fieldFilter); } } solrQuery.setIncludeScore(false); solrQuery.setHighlight(false); solrQuery.setTerms(false); solrQuery.setFacet(false); return solrQuery; } private String buildQuery(EventFilter filter, EventFilter exclusionFilter) throws ZepException { final StringBuilder sb = new StringBuilder(); if (filter == null) sb.append("*:*"); else sb.append("(").append(buildQueryFromFilter(filter)).append(")"); if (exclusionFilter != null) { String exclusionQuery = buildQueryFromFilter(exclusionFilter); if (exclusionQuery != null && !exclusionQuery.isEmpty()) sb.append(" AND NOT (").append(exclusionQuery).append(")"); } final String query = sb.toString(); logger.debug("Filter: {}, Exclusion filter: {}, Query: {}", new Object[]{filter, exclusionFilter, query}); return query; } private String buildQueryFromFilter(EventFilter filter) throws ZepException { if (filter == null) return null; SolrQueryBuilder qb = new SolrQueryBuilder(indexedDetailsConfiguration); qb.addFilter(filter); return qb.build(); } @Override protected void searchEventTagSeverities(EventFilter filter, final EventTagSeverityCounter counter) throws ZepException { assertReady(); if (filter.getTagFilterCount() == 0) { SolrQuery solrQuery = buildSolrQuery(filter, null, null, null, null, SolrFieldFilter.DEFAULTS); solrQuery.setRows(0); solrQuery.setFields(); solrQuery.setFacet(true); solrQuery.setFacetMinCount(1); solrQuery.setFacetLimit(-1); solrQuery.addFacetPivotField( IndexConstants.FIELD_ELEMENT_IDENTIFIER, IndexConstants.FIELD_SEVERITY, IndexConstants.FIELD_STATUS, IndexConstants.FIELD_COUNT); try { QueryResponse response = queryServer.query(solrQuery); for (PivotField pivotElementId : response.getFacetPivot().getVal(0)) { final String uuid = (String) pivotElementId.getValue(); for (PivotField pivotSeverity : pivotElementId.getPivot()) { final EventSeverity severity = EventSeverity.valueOf(Integer.parseInt((String) pivotSeverity.getValue())); for (PivotField pivotStatus : pivotSeverity.getPivot()) { final EventStatus status = EventStatus.valueOf(Integer.parseInt((String) pivotStatus.getValue())); final boolean acknowledged = EventStatus.STATUS_ACKNOWLEDGED.equals(status); for (PivotField pivotCount : pivotStatus.getPivot()) { final Integer count = pivotCount.getCount() * (Integer) pivotCount.getValue(); counter.update(uuid, severity, count, acknowledged); } } } } } catch (SolrServerException e) { throw new ZepException(e); } } else { SolrQuery solrQuery = buildSolrQuery(filter, null, null, null, null, SolrFieldFilter.SEARCH_EVENT_TAG_SEVERITIES); try { queryServer.queryAndStreamResponse(solrQuery, new StreamingResponseCallback() { @Override public void streamSolrDocument(SolrDocument doc) { final EventSeverity severity = EventSeverity.valueOf(Integer.parseInt((String) doc.getFieldValue(FIELD_SEVERITY))); final EventStatus status = EventStatus.valueOf(Integer.parseInt((String) doc.getFieldValue(FIELD_STATUS))); final boolean acknowledged = EventStatus.STATUS_ACKNOWLEDGED.equals(status); final int count = Integer.parseInt((String) doc.getFieldValue(FIELD_COUNT)); for (String fieldName : new String[]{FIELD_ELEMENT_IDENTIFIER, FIELD_ELEMENT_SUB_IDENTIFIER}) { final String uuid = (String) doc.getFieldValue(fieldName); counter.update(uuid, severity, count, acknowledged); } for (Object tag : doc.getFieldValues(FIELD_TAGS)) { counter.update((String)tag, severity, count, acknowledged); } } @Override public void streamDocListInfo(long numFound, long start, Float maxScore) { // ignored } }); } catch (SolrServerException e) { throw new ZepException(e); } catch (IOException e) { throw new ZepException(e); } } } private List<SortClause> createSortClauses(EventSort sort) throws ZepException { SolrQuery.ORDER order = (sort.getDirection() == EventSort.Direction.ASCENDING) ? ORDER.asc : ORDER.desc; Field field = sort.getField(); if (field == Field.DETAIL) { EventDetailItem item = indexedDetailsConfiguration.getEventDetailItemsByName().get(sort.getDetailKey()); if (item == null) { throw new IllegalArgumentException("Unknown event detail: " + sort.getDetailKey()); } final String fieldName = SolrEventIndexMapper.DETAIL_INDEX_PREFIX + sort.getDetailKey(); switch (item.getType()) { case STRING: return Lists.newArrayList(SortClause.create(fieldName + "_s_sort", order)); case DOUBLE: return Lists.newArrayList(SortClause.create(fieldName + "_d", order)); case INTEGER: return Lists.newArrayList(SortClause.create(fieldName + "_i", order)); case FLOAT: return Lists.newArrayList(SortClause.create(fieldName + "_f", order)); case LONG: return Lists.newArrayList(SortClause.create(fieldName + "_l", order)); case IP_ADDRESS: return Lists.newArrayList( SortClause.create(fieldName + "_ip_type", order), SortClause.create(fieldName + "_ip_sort", order)); case PATH: //ignored, because some path fields (zenoss.device.group) are multi-valued. return Collections.emptyList(); default: throw new IllegalArgumentException("Unsupported detail type: " + item.getType()); } } else { String sortField = SORT_MAP.get(field); if (sortField == null) throw new IllegalArgumentException("Unsupported sort field: " + field); return Lists.newArrayList(SortClause.create(sortField, order)); } } }