org.codelibs.elasticsearch.search.searchafter.SearchAfterBuilder Maven / Gradle / Ivy
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.codelibs.elasticsearch.search.searchafter;
import org.apache.lucene.search.FieldDoc;
import org.apache.lucene.search.SortField;
import org.codelibs.elasticsearch.ElasticsearchException;
import org.codelibs.elasticsearch.common.ParseField;
import org.codelibs.elasticsearch.common.ParseFieldMatcher;
import org.codelibs.elasticsearch.common.ParsingException;
import org.codelibs.elasticsearch.common.io.stream.StreamInput;
import org.codelibs.elasticsearch.common.io.stream.StreamOutput;
import org.codelibs.elasticsearch.common.io.stream.Writeable;
import org.codelibs.elasticsearch.common.text.Text;
import org.codelibs.elasticsearch.common.xcontent.ToXContent;
import org.codelibs.elasticsearch.common.xcontent.XContentBuilder;
import org.codelibs.elasticsearch.common.xcontent.XContentFactory;
import org.codelibs.elasticsearch.common.xcontent.XContentParser;
import org.codelibs.elasticsearch.index.fielddata.IndexFieldData;
import org.codelibs.elasticsearch.search.DocValueFormat;
import org.codelibs.elasticsearch.search.sort.SortAndFormats;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
*
*/
public class SearchAfterBuilder implements ToXContent, Writeable {
public static final ParseField SEARCH_AFTER = new ParseField("search_after");
private static final Object[] EMPTY_SORT_VALUES = new Object[0];
private Object[] sortValues = EMPTY_SORT_VALUES;
public SearchAfterBuilder() {
}
/**
* Read from a stream.
*/
public SearchAfterBuilder(StreamInput in) throws IOException {
int size = in.readVInt();
sortValues = new Object[size];
for (int i = 0; i < size; i++) {
sortValues[i] = in.readGenericValue();
}
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(sortValues.length);
for (Object fieldValue : sortValues) {
out.writeGenericValue(fieldValue);
}
}
public SearchAfterBuilder setSortValues(Object[] values) {
if (values == null) {
throw new NullPointerException("Values cannot be null.");
}
if (values.length == 0) {
throw new IllegalArgumentException("Values must contains at least one value.");
}
for (Object value : values) {
if (value == null) {
continue;
}
if (value instanceof String) {
continue;
}
if (value instanceof Text) {
continue;
}
if (value instanceof Long) {
continue;
}
if (value instanceof Integer) {
continue;
}
if (value instanceof Short) {
continue;
}
if (value instanceof Byte) {
continue;
}
if (value instanceof Double) {
continue;
}
if (value instanceof Float) {
continue;
}
if (value instanceof Boolean) {
continue;
}
if (value instanceof Boolean) {
continue;
}
throw new IllegalArgumentException("Can't handle " + SEARCH_AFTER + " field value of type [" + value.getClass() + "]");
}
sortValues = new Object[values.length];
System.arraycopy(values, 0, sortValues, 0, values.length);
return this;
}
public Object[] getSortValues() {
return Arrays.copyOf(sortValues, sortValues.length);
}
public static FieldDoc buildFieldDoc(SortAndFormats sort, Object[] values) {
if (sort == null || sort.sort.getSort() == null || sort.sort.getSort().length == 0) {
throw new IllegalArgumentException("Sort must contain at least one field.");
}
SortField[] sortFields = sort.sort.getSort();
if (sortFields.length != values.length) {
throw new IllegalArgumentException(
SEARCH_AFTER.getPreferredName() + " has " + values.length + " value(s) but sort has "
+ sort.sort.getSort().length + ".");
}
Object[] fieldValues = new Object[sortFields.length];
for (int i = 0; i < sortFields.length; i++) {
SortField sortField = sortFields[i];
DocValueFormat format = sort.formats[i];
if (values[i] != null) {
fieldValues[i] = convertValueFromSortField(values[i], sortField, format);
} else {
fieldValues[i] = null;
}
}
/*
* We set the doc id to Integer.MAX_VALUE in order to make sure that the search starts "after" the first document that is equal to
* the field values.
*/
return new FieldDoc(Integer.MAX_VALUE, 0, fieldValues);
}
private static Object convertValueFromSortField(Object value, SortField sortField, DocValueFormat format) {
if (sortField.getComparatorSource() instanceof IndexFieldData.XFieldComparatorSource) {
IndexFieldData.XFieldComparatorSource cmpSource = (IndexFieldData.XFieldComparatorSource) sortField.getComparatorSource();
return convertValueFromSortType(sortField.getField(), cmpSource.reducedType(), value, format);
}
return convertValueFromSortType(sortField.getField(), sortField.getType(), value, format);
}
private static Object convertValueFromSortType(String fieldName, SortField.Type sortType, Object value, DocValueFormat format) {
try {
switch (sortType) {
case DOC:
if (value instanceof Number) {
return ((Number) value).intValue();
}
return Integer.parseInt(value.toString());
case SCORE:
if (value instanceof Number) {
return ((Number) value).floatValue();
}
return Float.parseFloat(value.toString());
case INT:
if (value instanceof Number) {
return ((Number) value).intValue();
}
return Integer.parseInt(value.toString());
case DOUBLE:
if (value instanceof Number) {
return ((Number) value).doubleValue();
}
return Double.parseDouble(value.toString());
case LONG:
if (value instanceof Number) {
return ((Number) value).longValue();
}
return Long.parseLong(value.toString());
case FLOAT:
if (value instanceof Number) {
return ((Number) value).floatValue();
}
return Float.parseFloat(value.toString());
case STRING_VAL:
case STRING:
return format.parseBytesRef(value.toString());
default:
throw new IllegalArgumentException("Comparator type [" + sortType.name() + "] for field [" + fieldName
+ "] is not supported.");
}
} catch(NumberFormatException e) {
throw new IllegalArgumentException(
"Failed to parse " + SEARCH_AFTER.getPreferredName() + " value for field [" + fieldName + "].", e);
}
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
innerToXContent(builder);
builder.endObject();
return builder;
}
void innerToXContent(XContentBuilder builder) throws IOException {
builder.array(SEARCH_AFTER.getPreferredName(), sortValues);
}
public static SearchAfterBuilder fromXContent(XContentParser parser, ParseFieldMatcher parseFieldMatcher) throws IOException {
SearchAfterBuilder builder = new SearchAfterBuilder();
XContentParser.Token token = parser.currentToken();
List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy