// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.grouping;
import com.yahoo.component.chain.dependencies.After;
import com.yahoo.component.chain.dependencies.Before;
import com.yahoo.component.chain.dependencies.Provides;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.grouping.request.GroupingOperation;
import com.yahoo.search.searchchain.Execution;
import com.yahoo.search.searchchain.PhaseNames;
import java.util.*;
/**
* This searcher is responsible for turning the "select" parameter into a corresponding {@link GroupingRequest}. It will
* also parse any "timezone" parameter as the timezone for time expressions such as {@link
* com.yahoo.search.grouping.request.DayOfMonthFunction} and {@link com.yahoo.search.grouping.request.HourOfDayFunction}.
*
* @author Simon Thoresen
*/
@After(PhaseNames.RAW_QUERY)
@Before(PhaseNames.TRANSFORMED_QUERY)
@Provides(GroupingQueryParser.SELECT_PARAMETER_PARSING)
public class GroupingQueryParser extends Searcher {
public static final String SELECT_PARAMETER_PARSING = "SelectParameterParsing";
public static final CompoundName PARAM_CONTINUE = new CompoundName("continue");
public static final CompoundName PARAM_REQUEST = new CompoundName("select");
public static final CompoundName PARAM_TIMEZONE = new CompoundName("timezone");
private static final ThreadLocal zoneCache = new ThreadLocal<>();
@Override
public Result search(Query query, Execution execution) {
String reqParam = query.properties().getString(PARAM_REQUEST);
if (reqParam == null) {
return execution.search(query);
}
List continuations = getContinuations(query.properties().getString(PARAM_CONTINUE));
TimeZone zone = getTimeZone(query.properties().getString(PARAM_TIMEZONE, "utc"));
for (GroupingOperation op : GroupingOperation.fromStringAsList(reqParam)) {
GroupingRequest grpRequest = GroupingRequest.newInstance(query);
grpRequest.setRootOperation(op);
grpRequest.setTimeZone(zone);
grpRequest.continuations().addAll(continuations);
}
return execution.search(query);
}
private List getContinuations(String param) {
if (param == null) {
return Collections.emptyList();
}
List ret = new LinkedList<>();
for (String str : param.split(" ")) {
ret.add(Continuation.fromString(str));
}
return ret;
}
private TimeZone getTimeZone(String name) {
ZoneCache cache = zoneCache.get();
if (cache == null) {
cache = new ZoneCache();
zoneCache.set(cache);
}
TimeZone timeZone = cache.get(name);
if (timeZone == null) {
timeZone = TimeZone.getTimeZone(name);
cache.put(name, timeZone);
}
return timeZone;
}
@SuppressWarnings("serial")
private static class ZoneCache extends LinkedHashMap {
ZoneCache() {
super(16, 0.75f, true);
}
@Override
protected boolean removeEldestEntry(Map.Entry entry) {
return size() > 128; // large enough to cache common cases
}
}
}