org.graylog2.restclient.models.UniversalSearch Maven / Gradle / Ivy
The newest version!
/**
* This file is part of Graylog.
*
* Graylog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Graylog is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Graylog. If not, see .
*/
package org.graylog2.restclient.models;
import com.google.common.base.Joiner;
import com.google.common.net.MediaType;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import org.graylog2.restclient.lib.APIException;
import org.graylog2.restclient.lib.ApiClient;
import org.graylog2.restclient.lib.ApiRequestBuilder;
import org.graylog2.restclient.lib.timeranges.TimeRange;
import org.graylog2.restclient.models.api.responses.DateHistogramResponse;
import org.graylog2.restclient.models.api.responses.FieldHistogramResponse;
import org.graylog2.restclient.models.api.responses.FieldStatsResponse;
import org.graylog2.restclient.models.api.responses.FieldTermsResponse;
import org.graylog2.restclient.models.api.responses.SearchResultResponse;
import org.graylog2.restclient.models.api.results.DateHistogramResult;
import org.graylog2.restclient.models.api.results.SearchResult;
import org.graylog2.restroutes.PathMethod;
import org.graylog2.restroutes.generated.routes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.graylog2.restclient.lib.Configuration.apiTimeout;
public class UniversalSearch {
private static final Logger log = LoggerFactory.getLogger(UniversalSearch.class);
public static final int PER_PAGE = 100;
public static final int KEITH = 61; // http://en.wikipedia.org/wiki/61_(number) -> Keith
public static final SearchSort DEFAULT_SORT = new SearchSort("timestamp", SearchSort.Direction.DESC);
private final ApiClient api;
private final String query;
private final FieldMapper fieldMapper;
private final String filter;
private final TimeRange timeRange;
private final Integer page;
private final SearchSort order;
@AssistedInject
private UniversalSearch(ApiClient api, FieldMapper fieldMapper, @Assisted TimeRange timeRange, @Assisted String query) {
this(api, fieldMapper, timeRange, query, 0);
}
@AssistedInject
private UniversalSearch(ApiClient api, FieldMapper fieldMapper, @Assisted TimeRange timeRange, @Assisted String query, @Assisted Integer page) {
this(api, fieldMapper, timeRange, query, page, null, null);
}
@AssistedInject
private UniversalSearch(ApiClient api, FieldMapper fieldMapper, @Assisted String query, @Assisted TimeRange timeRange, @Nullable @Assisted("filter") String filter) {
this(api, fieldMapper, timeRange, query, 0, filter, null);
}
@AssistedInject
public UniversalSearch(ApiClient api, FieldMapper fieldMapper, @Assisted TimeRange timeRange, @Assisted("query") String query, @Assisted Integer page, @Assisted("filter") String filter) {
this(api, fieldMapper,timeRange, query, page, filter, null);
}
@AssistedInject
public UniversalSearch(ApiClient api, FieldMapper fieldMapper, @Assisted TimeRange timeRange, @Assisted String query, @Assisted Integer page, @Assisted SearchSort order) {
this(api, fieldMapper, timeRange, query, page, null, order);
}
@AssistedInject
private UniversalSearch(ApiClient api, FieldMapper fieldMapper, @Assisted TimeRange timeRange, @Assisted("query") String query, @Assisted Integer page, @Assisted("filter") String filter, @Assisted SearchSort order) {
this.fieldMapper = fieldMapper;
this.filter = filter;
this.api = api;
this.query = query;
this.timeRange = timeRange;
if (page == 0) {
this.page = 0;
} else {
this.page = page - 1;
}
if (order == null) {
this.order = DEFAULT_SORT;
} else {
this.order = order;
}
}
private T doSearch(Class clazz, MediaType mediaType, int pageSize, Set selectedFields) throws APIException, IOException {
final ApiRequestBuilder builder = getSearchRequestBuilder(clazz, pageSize, selectedFields);
return builder
.accept(mediaType)
.timeout(KEITH, TimeUnit.SECONDS)
.expect(200, 400)
.execute();
}
private ApiRequestBuilder getSearchRequestBuilder(Class clazz, int pageSize, Set selectedFields) {
PathMethod pathMethod;
switch (timeRange.getType()) {
case ABSOLUTE:
pathMethod = routes.AbsoluteSearchResource().searchAbsolute();
break;
case KEYWORD:
pathMethod = routes.KeywordSearchResource().searchKeyword();
break;
case RELATIVE:
pathMethod = routes.RelativeSearchResource().searchRelative();
break;
default:
throw new RuntimeException("Invalid time range type!");
}
final ApiRequestBuilder builder = api.path(pathMethod, clazz)
.queryParams(timeRange.getQueryParams())
.queryParam("query", query)
.queryParam("limit", pageSize)
.queryParam("offset", page * pageSize)
.queryParam("sort", order.toApiParam());
addFilterQueryParam(builder);
if (selectedFields != null && !selectedFields.isEmpty()) {
builder.queryParam("fields", Joiner.on(',').skipNulls().join(selectedFields));
}
return builder;
}
public SearchResult search() throws IOException, APIException {
SearchResultResponse response = doSearch(SearchResultResponse.class, MediaType.JSON_UTF_8, PER_PAGE, null);
if (response == null) {
log.error("We should never get an empty result without throwing an IOException.");
throw new APIException(null, null, new RuntimeException("Empty search response, this is likely a bug in exception handling."));
}
return new SearchResult(
query,
response.builtQuery,
timeRange,
response.total_results,
response.time,
response.messages,
response.fields,
response.usedIndices,
response.getFromDataTime(),
response.getToDataTime(),
fieldMapper
);
}
public InputStream searchAsCsv(Set selectedFields) throws IOException, APIException {
final ApiRequestBuilder builder = getSearchRequestBuilder(String.class,
Integer.MAX_VALUE,
selectedFields);
return builder.accept(MediaType.CSV_UTF_8)
.timeout(Long.MAX_VALUE, TimeUnit.SECONDS) // never time out
.expect(200, 400)
.executeStreaming();
}
public DateHistogramResult dateHistogram(String interval) throws IOException, APIException {
PathMethod routePath;
switch (timeRange.getType()) {
case ABSOLUTE:
routePath = routes.AbsoluteSearchResource().histogramAbsolute();
break;
case KEYWORD:
routePath = routes.KeywordSearchResource().histogramKeyword();
break;
case RELATIVE:
routePath = routes.RelativeSearchResource().histogramRelative();
break;
default:
throw new RuntimeException("Invalid time range type!");
}
final ApiRequestBuilder builder = api.path(routePath, DateHistogramResponse.class)
.queryParam("interval", interval)
.queryParam("query", query)
.queryParams(timeRange.getQueryParams())
.timeout(apiTimeout("search_universal_histogram", KEITH, TimeUnit.SECONDS));
addFilterQueryParam(builder);
final DateHistogramResponse response = builder.execute();
return new DateHistogramResult(
response.query,
response.time,
response.interval,
response.results,
response.getHistogramBoundaries(),
timeRange
);
}
public FieldStatsResponse fieldStats(String field) throws IOException, APIException {
PathMethod routePath;
switch (timeRange.getType()) {
case ABSOLUTE:
routePath = routes.AbsoluteSearchResource().statsAbsolute();
break;
case KEYWORD:
routePath = routes.KeywordSearchResource().statsKeyword();
break;
case RELATIVE:
routePath = routes.RelativeSearchResource().statsRelative();
break;
default:
throw new RuntimeException("Invalid time range type!");
}
final ApiRequestBuilder builder = api.path(routePath, FieldStatsResponse.class)
.queryParam("field", field)
.queryParam("query", query)
.queryParams(timeRange.getQueryParams())
.timeout(apiTimeout("search_universal_stats", KEITH, TimeUnit.SECONDS));
addFilterQueryParam(builder);
return builder.execute();
}
public FieldTermsResponse fieldTerms(String field) throws IOException, APIException {
PathMethod routePath;
switch (timeRange.getType()) {
case ABSOLUTE:
routePath = routes.AbsoluteSearchResource().termsAbsolute();
break;
case KEYWORD:
routePath = routes.KeywordSearchResource().termsKeyword();
break;
case RELATIVE:
routePath = routes.RelativeSearchResource().termsRelative();
break;
default:
throw new RuntimeException("Invalid time range type!");
}
final ApiRequestBuilder builder = api.path(routePath, FieldTermsResponse.class)
.queryParam("field", field)
.queryParam("query", query)
.queryParams(timeRange.getQueryParams())
.timeout(apiTimeout("search_universal_terms", KEITH, TimeUnit.SECONDS));
addFilterQueryParam(builder);
return builder.execute();
}
public FieldHistogramResponse fieldHistogram(String field, String interval, boolean isCardinality) throws IOException, APIException {
PathMethod routePath;
switch (timeRange.getType()) {
case ABSOLUTE:
routePath = routes.AbsoluteSearchResource().fieldHistogramAbsolute();
break;
case KEYWORD:
routePath = routes.KeywordSearchResource().fieldHistogramKeyword();
break;
case RELATIVE:
routePath = routes.RelativeSearchResource().fieldHistogramRelative();
break;
default:
throw new RuntimeException("Invalid time range type!");
}
final ApiRequestBuilder builder = api.path(routePath, FieldHistogramResponse.class)
.queryParam("field", field)
.queryParam("interval", interval)
.queryParam("query", query)
.queryParams(timeRange.getQueryParams())
.queryParam("cardinality", Boolean.toString(isCardinality))
.timeout(apiTimeout("search_universal_fieldhistogram", KEITH, TimeUnit.SECONDS));
addFilterQueryParam(builder);
return builder.execute();
}
private void addFilterQueryParam(ApiRequestBuilder> builder) {
if (filter != null) {
builder.queryParam("filter", filter);
}
}
public SearchSort getOrder() {
return order;
}
public String getQuery() {
return query;
}
public String getFilter() {
return filter;
}
public TimeRange getTimeRange() {
return timeRange;
}
public interface Factory {
UniversalSearch queryWithRange(String query, TimeRange timeRange);
UniversalSearch queryWithRangeAndFilter(String query, TimeRange timeRange, @Assisted("filter") String filter);
UniversalSearch queryWithRangePageAndOrder(String query, TimeRange timeRange, Integer page, SearchSort order);
UniversalSearch queryWithFilterRangeAndPage(@Assisted("query") String query, @Assisted("filter") String filter, TimeRange timeRange, Integer page);
UniversalSearch queryWithFilterRangePageAndOrder(@Assisted("query") String query, @Assisted("filter") String filter, TimeRange timeRange, Integer page, SearchSort order);
}
}