Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.codelibs.elasticsearch.taste.rest.TasteSearchRestAction Maven / Gradle / Ivy
package org.codelibs.elasticsearch.taste.rest;
import static org.codelibs.elasticsearch.util.action.ListenerUtils.on;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.codelibs.elasticsearch.taste.TasteConstants;
import org.codelibs.elasticsearch.taste.exception.NotFoundException;
import org.codelibs.elasticsearch.taste.exception.OperationFailedException;
import org.codelibs.elasticsearch.taste.exception.TasteException;
import org.codelibs.elasticsearch.util.action.ListenerUtils.OnResponseListener;
import org.codelibs.elasticsearch.util.lang.StringUtils;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.cache.Cache;
import org.elasticsearch.common.cache.CacheBuilder;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHitField;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
public class TasteSearchRestAction extends BaseRestHandler {
private Cache> cache;
@Inject
public TasteSearchRestAction(final Settings settings, final Client client,
final RestController restController) {
super(settings, client);
final String size = settings.get("taste.cache.search.size", "1000");
final String duration = settings.get("taste.cache.search.duration",
"600000"); // 10min
cache = CacheBuilder
.newBuilder()
.expireAfterAccess(Long.parseLong(duration),
TimeUnit.MILLISECONDS)
.maximumSize(Long.parseLong(size)).build();
restController.registerHandler(RestRequest.Method.GET,
"/{index}/_taste/{objectType}/{systemId}", this);
restController.registerHandler(RestRequest.Method.GET,
"/{index}/{type}/_taste/{objectType}/{systemId}", this);
}
@Override
protected void handleRequest(final RestRequest request,
final RestChannel channel, final Client client) {
final Info info = new Info(request);
final String systemId = request.param("systemId");
if (StringUtils.isBlank(systemId)) {
onError(channel, new NotFoundException("No system_id."));
return;
}
if (info.getIdIndex() == null) {
onError(channel, new NotFoundException("No search type."));
return;
}
final OnResponseListener responseListener = searchResponse -> {
final SearchHits hits = searchResponse.getHits();
if (hits.totalHits() == 0) {
onError(channel,
new NotFoundException("No " + info.getIdField()
+ " data for " + systemId + " in "
+ info.getIdIndex() + "/" + info.getIdType()));
return;
}
final SearchHit hit = hits.getHits()[0];
final SearchHitField field = hit.field(info.getIdField());
final Number targetId = field.getValue();
if (targetId == null) {
onError(channel,
new NotFoundException("No " + info.getIdField()
+ " for " + systemId + " in "
+ info.getIdIndex() + "/" + info.getIdType()));
return;
}
doSearchRequest(request, channel, client, info,
targetId.longValue());
};
client.prepareSearch(info.getIdIndex()).setTypes(info.getIdType())
.setQuery(QueryBuilders.termQuery("system_id", systemId))
.addField(info.getIdField())
.addSort(info.getTimestampField(), SortOrder.DESC)
.execute(on(responseListener, t -> onError(channel, t)));
}
private void doSearchRequest(final RestRequest request,
final RestChannel channel, final Client client, final Info info,
final long targetId) {
final OnResponseListener responseListener = response -> {
final SearchHits hits = response.getHits();
if (hits.totalHits() == 0) {
onError(channel,
new NotFoundException("No ID for " + targetId + " in "
+ info.getTargetIndex() + "/"
+ info.getTargetType()));
return;
}
try {
final XContentBuilder builder = jsonBuilder();
final String pretty = request.param("pretty");
if (pretty != null && !"false".equalsIgnoreCase(pretty)) {
builder.prettyPrint().lfAtEnd();
}
builder.startObject()//
.field("took", response.getTookInMillis())//
.field("timed_out", response.isTimedOut())//
.startObject("_shards")//
.field("total", response.getTotalShards())//
.field("successful", response.getSuccessfulShards())//
.field("failed", response.getFailedShards())//
.endObject()//
.startObject("hits")//
.field("total", hits.getTotalHits())//
.field("max_score", hits.getMaxScore())//
.startArray("hits");
for (final SearchHit hit : hits.getHits()) {
final Map source = expandObjects(client,
hit.getSource(), info);
builder.startObject()//
.field("_index", hit.getIndex())//
.field("_type", hit.getType())//
.field("_id", hit.getId())//
.field("_score", hit.getScore())//
.field("_source", source)//
.endObject();//
}
builder.endArray()//
.endObject()//
.endObject();
channel.sendResponse(new BytesRestResponse(RestStatus.OK,
builder));
} catch (final IOException e) {
throw new OperationFailedException(
"Failed to build a response.", e);
}
};
client.prepareSearch(info.getTargetIndex())
.setTypes(info.getTargetType())
.setQuery(
QueryBuilders.termQuery(info.getTargetIdField(),
targetId))
.addSort(info.getTimestampField(), SortOrder.DESC)
.setSize(info.getSize()).setFrom(info.getFrom())
.execute(on(responseListener, t -> onError(channel, t)));
}
private Map expandObjects(final Client client,
final Map source, final Info info) {
final Map newSource = new HashMap<>(source.size());
for (final Map.Entry entry : source.entrySet()) {
final Object value = entry.getValue();
if (info.getUserIdField().equals(entry.getKey()) && value != null) {
final Number targetId = (Number) value;
final Map objMap = getObjectMap(client, "U-",
info.getUserIndex(), info.getUserType(),
targetId.toString());
newSource.put("user", objMap);
} else if (info.getItemIdField().equals(entry.getKey())
&& value != null) {
final Number targetId = (Number) value;
final Map objMap = getObjectMap(client, "I-",
info.getItemIndex(), info.getItemType(),
targetId.toString());
newSource.put("item", objMap);
} else if (value instanceof Map) {
@SuppressWarnings("unchecked")
final Map objMap = (Map) value;
newSource.put(entry.getKey(),
expandObjects(client, objMap, info));
} else if (value instanceof List) {
@SuppressWarnings("unchecked")
final List list = (List) value;
final List newList = new ArrayList<>(list.size());
for (final Object obj : list) {
if (obj instanceof Map) {
@SuppressWarnings("unchecked")
final Map objMap = (Map) obj;
newList.add(expandObjects(client, objMap, info));
} else {
newList.add(obj);
}
}
newSource.put(entry.getKey(), newList);
} else {
newSource.put(entry.getKey(), value);
}
}
return newSource;
}
private Map getObjectMap(final Client client,
final String prefix, final String index, final String type,
final String id) {
try {
return cache.get(prefix + id, () -> {
final GetResponse response = client.prepareGet(index, type, id)
.execute().actionGet();
if (response.isExists()) {
return response.getSource();
}
return null;
});
} catch (final ExecutionException e) {
throw new TasteException("Failed to get data for " + index + "/"
+ type + "/" + id, e);
}
}
private void onError(final RestChannel channel, final Throwable t) {
try {
channel.sendResponse(new BytesRestResponse(channel, t));
} catch (final Exception e) {
logger.error("Failed to send a failure response.", e);
}
}
private static class Info {
private static final String ITEM = "item";
private static final String USER = "user";
private String targetIndex;
private String targetType;
private String targetIdField;
private String userIndex;
private String userType;
private String userIdField;
private String itemIndex;
private String itemType;
private String itemIdField;
private String idIndex;
private String idType;
private String idField;
private String timestampField;
private String objectType;
private int size;
private int from;
Info(final RestRequest request) {
size = request.paramAsInt("size", 10);
from = request.paramAsInt("from", 0);
targetIndex = request.param("index");
targetType = request.param("type");
userIndex = request.param(TasteConstants.REQUEST_PARAM_USER_INDEX,
targetIndex);
userType = request.param(TasteConstants.REQUEST_PARAM_USER_TYPE,
TasteConstants.USER_TYPE);
itemIndex = request.param(TasteConstants.REQUEST_PARAM_ITEM_INDEX,
targetIndex);
itemType = request.param(TasteConstants.REQUEST_PARAM_ITEM_TYPE,
TasteConstants.ITEM_TYPE);
userIdField = request.param(
TasteConstants.REQUEST_PARAM_USER_ID_FIELD,
TasteConstants.USER_ID_FIELD);
itemIdField = request.param(
TasteConstants.REQUEST_PARAM_ITEM_ID_FIELD,
TasteConstants.ITEM_ID_FIELD);
timestampField = request.param(
TasteConstants.REQUEST_PARAM_TIMESTAMP_FIELD,
TasteConstants.TIMESTAMP_FIELD);
objectType = request.param("objectType");
if (USER.equals(objectType)) {
idIndex = userIndex;
idType = userType;
idField = request.param(TasteConstants.REQUEST_PARAM_ID_FIELD,
userIdField);
} else if (ITEM.equals(objectType)) {
idIndex = itemIndex;
idType = itemType;
idField = request.param(TasteConstants.REQUEST_PARAM_ID_FIELD,
itemIdField);
}
targetIdField = request.param(
TasteConstants.REQUEST_PARAM_TARGET_ID_FIELD, idField);
}
public int getFrom() {
return from;
}
public int getSize() {
return size;
}
public String getTargetIndex() {
return targetIndex;
}
public String getTargetType() {
return targetType;
}
public String getTargetIdField() {
return targetIdField;
}
public String getUserIndex() {
return userIndex;
}
public String getUserType() {
return userType;
}
public String getItemIndex() {
return itemIndex;
}
public String getItemType() {
return itemType;
}
public String getUserIdField() {
return userIdField;
}
public String getItemIdField() {
return itemIdField;
}
public String getTimestampField() {
return timestampField;
}
public String getIdIndex() {
return idIndex;
}
public String getIdType() {
return idType;
}
public String getIdField() {
return idField;
}
}
}