/*****************************************************************************
*
* 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));
}
}
}