have index level query boost part of the search source
This commit is contained in:
parent
284a35131c
commit
929bb3f2be
|
@ -26,8 +26,6 @@ import org.elasticsearch.search.builder.SearchSourceBuilder;
|
|||
import org.elasticsearch.util.Required;
|
||||
import org.elasticsearch.util.Strings;
|
||||
import org.elasticsearch.util.TimeValue;
|
||||
import org.elasticsearch.util.gnu.trove.TObjectFloatHashMap;
|
||||
import org.elasticsearch.util.gnu.trove.TObjectFloatIterator;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
|
@ -42,8 +40,6 @@ import static org.elasticsearch.util.TimeValue.*;
|
|||
*/
|
||||
public class SearchRequest implements ActionRequest {
|
||||
|
||||
private static TObjectFloatHashMap<String> EMPTY = new TObjectFloatHashMap<String>();
|
||||
|
||||
private SearchType searchType = SearchType.QUERY_THEN_FETCH;
|
||||
|
||||
private String[] indices;
|
||||
|
@ -60,8 +56,6 @@ public class SearchRequest implements ActionRequest {
|
|||
|
||||
private String[] types = Strings.EMPTY_ARRAY;
|
||||
|
||||
private TObjectFloatHashMap<String> indexBoost = EMPTY;
|
||||
|
||||
private TimeValue timeout;
|
||||
|
||||
private boolean listenerThreaded = false;
|
||||
|
@ -188,22 +182,6 @@ public class SearchRequest implements ActionRequest {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic query boost on an index level query. Very handy when, for example, each user has
|
||||
* his own index, and friends matter more than friends of friends.
|
||||
*/
|
||||
public TObjectFloatHashMap<String> indexBoost() {
|
||||
return indexBoost;
|
||||
}
|
||||
|
||||
public SearchRequest indexBoost(String index, float indexBoost) {
|
||||
if (this.indexBoost == EMPTY) {
|
||||
this.indexBoost = new TObjectFloatHashMap<String>();
|
||||
}
|
||||
this.indexBoost.put(index, indexBoost);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
@ -237,16 +215,6 @@ public class SearchRequest implements ActionRequest {
|
|||
source = new byte[in.readInt()];
|
||||
in.readFully(source);
|
||||
|
||||
int size = in.readInt();
|
||||
if (size == 0) {
|
||||
indexBoost = EMPTY;
|
||||
} else {
|
||||
indexBoost = new TObjectFloatHashMap<String>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
indexBoost.put(in.readUTF(), in.readFloat());
|
||||
}
|
||||
}
|
||||
|
||||
int typesSize = in.readInt();
|
||||
if (typesSize > 0) {
|
||||
types = new String[typesSize];
|
||||
|
@ -288,16 +256,6 @@ public class SearchRequest implements ActionRequest {
|
|||
}
|
||||
out.writeInt(source.length);
|
||||
out.write(source);
|
||||
if (indexBoost == null) {
|
||||
out.writeInt(0);
|
||||
} else {
|
||||
out.writeInt(indexBoost.size());
|
||||
for (TObjectFloatIterator<String> it = indexBoost.iterator(); it.hasNext();) {
|
||||
it.advance();
|
||||
out.writeUTF(it.key());
|
||||
out.writeFloat(it.value());
|
||||
}
|
||||
}
|
||||
out.writeInt(types.length);
|
||||
for (String type : types) {
|
||||
out.writeUTF(type);
|
||||
|
|
|
@ -63,11 +63,6 @@ public abstract class TransportSearchHelper {
|
|||
InternalSearchRequest internalRequest = new InternalSearchRequest(shardRouting, request.source());
|
||||
internalRequest.from(request.from()).size(request.size());
|
||||
internalRequest.scroll(request.scroll());
|
||||
if (request.indexBoost() != null) {
|
||||
if (request.indexBoost().containsKey(shardRouting.index())) {
|
||||
internalRequest.queryBoost(request.indexBoost().get(shardRouting.index()));
|
||||
}
|
||||
}
|
||||
internalRequest.timeout(request.timeout());
|
||||
internalRequest.types(request.types());
|
||||
return internalRequest;
|
||||
|
|
|
@ -148,6 +148,14 @@ public class NettyHttpRequest implements HttpRequest {
|
|||
return sValue.equals("true") || sValue.equals("1") || sValue.equals("on");
|
||||
}
|
||||
|
||||
@Override public Boolean paramAsBoolean(String key, Boolean defaultValue) {
|
||||
String sValue = param(key);
|
||||
if (sValue == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return sValue.equals("true") || sValue.equals("1") || sValue.equals("on");
|
||||
}
|
||||
|
||||
@Override public TimeValue paramAsTime(String key, TimeValue defaultValue) {
|
||||
return parseTimeValue(param(key), defaultValue);
|
||||
}
|
||||
|
|
|
@ -67,6 +67,8 @@ public interface RestRequest extends ToJson.Params {
|
|||
|
||||
boolean paramAsBoolean(String key, boolean defaultValue);
|
||||
|
||||
Boolean paramAsBoolean(String key, Boolean defaultValue);
|
||||
|
||||
TimeValue paramAsTime(String key, TimeValue defaultValue);
|
||||
|
||||
SizeValue paramAsSize(String key, SizeValue defaultValue);
|
||||
|
|
|
@ -143,24 +143,6 @@ public class RestSearchAction extends BaseRestHandler {
|
|||
searchRequest.size(Integer.parseInt(size));
|
||||
}
|
||||
|
||||
String sIndicesBoost = request.param("indicesBoost");
|
||||
if (sIndicesBoost != null) {
|
||||
String[] indicesBoost = indicesBoostPattern.split(sIndicesBoost);
|
||||
for (String indexBoost : indicesBoost) {
|
||||
int divisor = indexBoost.indexOf(',');
|
||||
if (divisor == -1) {
|
||||
throw new ElasticSearchIllegalArgumentException("Illegal index boost [" + indexBoost + "], no ','");
|
||||
}
|
||||
String indexName = indexBoost.substring(0, divisor);
|
||||
String sBoost = indexBoost.substring(divisor + 1);
|
||||
try {
|
||||
searchRequest.indexBoost(indexName, Float.parseFloat(sBoost));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ElasticSearchIllegalArgumentException("Illegal index boost [" + indexBoost + "], boost not a float number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String scroll = request.param("scroll");
|
||||
if (scroll != null) {
|
||||
searchRequest.scroll(new Scroll(parseTimeValue(scroll, null)));
|
||||
|
@ -237,6 +219,24 @@ public class RestSearchAction extends BaseRestHandler {
|
|||
}
|
||||
}
|
||||
|
||||
String sIndicesBoost = request.param("indicesBoost");
|
||||
if (sIndicesBoost != null) {
|
||||
String[] indicesBoost = indicesBoostPattern.split(sIndicesBoost);
|
||||
for (String indexBoost : indicesBoost) {
|
||||
int divisor = indexBoost.indexOf(',');
|
||||
if (divisor == -1) {
|
||||
throw new ElasticSearchIllegalArgumentException("Illegal index boost [" + indexBoost + "], no ','");
|
||||
}
|
||||
String indexName = indexBoost.substring(0, divisor);
|
||||
String sBoost = indexBoost.substring(divisor + 1);
|
||||
try {
|
||||
searchSourceBuilder.indexBoost(indexName, Float.parseFloat(sBoost));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ElasticSearchIllegalArgumentException("Illegal index boost [" + indexBoost + "], boost not a float number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add different parameters to the source
|
||||
return searchSourceBuilder.build();
|
||||
}
|
||||
|
|
|
@ -31,5 +31,10 @@ public interface SearchPhase {
|
|||
|
||||
Map<String, ? extends SearchParseElement> parseElements();
|
||||
|
||||
/**
|
||||
* Performs pre processing of the search context before the execute.
|
||||
*/
|
||||
void preProcess(SearchContext context);
|
||||
|
||||
void execute(SearchContext context) throws ElasticSearchException;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.elasticsearch.search.query.QuerySearchRequest;
|
|||
import org.elasticsearch.search.query.QuerySearchResult;
|
||||
import org.elasticsearch.timer.TimerService;
|
||||
import org.elasticsearch.util.TimeValue;
|
||||
import org.elasticsearch.util.Unicode;
|
||||
import org.elasticsearch.util.component.AbstractComponent;
|
||||
import org.elasticsearch.util.component.Lifecycle;
|
||||
import org.elasticsearch.util.component.LifecycleComponent;
|
||||
|
@ -245,7 +246,7 @@ public class SearchService extends AbstractComponent implements LifecycleCompone
|
|||
SearchShardTarget shardTarget = new SearchShardTarget(clusterService.state().nodes().localNodeId(), request.index(), request.shardId());
|
||||
|
||||
SearchContext context = new SearchContext(idGenerator.incrementAndGet(), shardTarget, request.timeout(),
|
||||
request.queryBoost(), request.source(), request.types(), engineSearcher, indexService);
|
||||
request.source(), request.types(), engineSearcher, indexService);
|
||||
|
||||
// init the from and size
|
||||
context.from(request.from());
|
||||
|
@ -263,6 +264,11 @@ public class SearchService extends AbstractComponent implements LifecycleCompone
|
|||
context.size(10);
|
||||
}
|
||||
|
||||
// pre process
|
||||
dfsPhase.preProcess(context);
|
||||
queryPhase.preProcess(context);
|
||||
fetchPhase.preProcess(context);
|
||||
|
||||
// compute the context keep alive
|
||||
TimeValue keepAlive = defaultKeepAlive;
|
||||
if (request.scroll() != null && request.scroll().keepAlive() != null) {
|
||||
|
@ -305,7 +311,7 @@ public class SearchService extends AbstractComponent implements LifecycleCompone
|
|||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SearchParseException(context, "Failed to parse [" + context.source() + "]", e);
|
||||
throw new SearchParseException(context, "Failed to parse [" + Unicode.fromBytes(context.source()) + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ package org.elasticsearch.search.builder;
|
|||
|
||||
import org.elasticsearch.index.query.json.JsonQueryBuilder;
|
||||
import org.elasticsearch.search.SearchException;
|
||||
import org.elasticsearch.util.gnu.trove.TObjectFloatHashMap;
|
||||
import org.elasticsearch.util.gnu.trove.TObjectFloatIterator;
|
||||
import org.elasticsearch.util.json.JsonBuilder;
|
||||
import org.elasticsearch.util.json.ToJson;
|
||||
|
||||
|
@ -59,6 +61,9 @@ public class SearchSourceBuilder {
|
|||
|
||||
private SearchSourceFacetsBuilder facetsBuilder;
|
||||
|
||||
private TObjectFloatHashMap<String> indexBoost = null;
|
||||
|
||||
|
||||
public SearchSourceBuilder() {
|
||||
}
|
||||
|
||||
|
@ -125,6 +130,15 @@ public class SearchSourceBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public SearchSourceBuilder indexBoost(String index, float indexBoost) {
|
||||
if (this.indexBoost == null) {
|
||||
this.indexBoost = new TObjectFloatHashMap<String>();
|
||||
}
|
||||
this.indexBoost.put(index, indexBoost);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public byte[] build() throws SearchException {
|
||||
try {
|
||||
JsonBuilder builder = binaryJsonBuilder();
|
||||
|
@ -176,6 +190,15 @@ public class SearchSourceBuilder {
|
|||
builder.endObject();
|
||||
}
|
||||
|
||||
if (indexBoost != null) {
|
||||
builder.startObject("queryBoost");
|
||||
for (TObjectFloatIterator<String> it = indexBoost.iterator(); it.hasNext();) {
|
||||
it.advance();
|
||||
builder.field(it.key(), it.value());
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
if (facetsBuilder != null) {
|
||||
facetsBuilder.toJson(builder, ToJson.EMPTY_PARAMS);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,9 @@ public class DfsPhase implements SearchPhase {
|
|||
return ImmutableMap.of();
|
||||
}
|
||||
|
||||
@Override public void preProcess(SearchContext context) {
|
||||
}
|
||||
|
||||
public void execute(SearchContext context) {
|
||||
try {
|
||||
context.rewriteQuery();
|
||||
|
|
|
@ -46,6 +46,9 @@ public class FacetsPhase implements SearchPhase {
|
|||
return ImmutableMap.of("facets", new FacetsParseElement());
|
||||
}
|
||||
|
||||
@Override public void preProcess(SearchContext context) {
|
||||
}
|
||||
|
||||
@Override public void execute(SearchContext context) throws ElasticSearchException {
|
||||
if (context.facets() == null) {
|
||||
return;
|
||||
|
|
|
@ -47,6 +47,9 @@ public class FetchPhase implements SearchPhase {
|
|||
return ImmutableMap.of("explain", new ExplainParseElement(), "fields", new FieldsParseElement());
|
||||
}
|
||||
|
||||
@Override public void preProcess(SearchContext context) {
|
||||
}
|
||||
|
||||
public void execute(SearchContext context) {
|
||||
FieldSelector fieldSelector = buildFieldSelectors(context);
|
||||
|
||||
|
|
|
@ -64,8 +64,6 @@ public class InternalSearchRequest implements Streamable {
|
|||
|
||||
private int size = -1;
|
||||
|
||||
private float queryBoost = 1.0f;
|
||||
|
||||
private TimeValue timeout;
|
||||
|
||||
private String[] types = Strings.EMPTY_ARRAY;
|
||||
|
@ -124,19 +122,6 @@ public class InternalSearchRequest implements Streamable {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a dynamic query boost on an index level query. Very handy when, for example, each user has
|
||||
* his own index, and friends matter more than friends of friends.
|
||||
*/
|
||||
public float queryBoost() {
|
||||
return queryBoost;
|
||||
}
|
||||
|
||||
public InternalSearchRequest queryBoost(float queryBoost) {
|
||||
this.queryBoost = queryBoost;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
@ -167,7 +152,6 @@ public class InternalSearchRequest implements Streamable {
|
|||
}
|
||||
source = new byte[in.readInt()];
|
||||
in.readFully(source);
|
||||
queryBoost = in.readFloat();
|
||||
int typesSize = in.readInt();
|
||||
if (typesSize > 0) {
|
||||
types = new String[typesSize];
|
||||
|
@ -196,7 +180,6 @@ public class InternalSearchRequest implements Streamable {
|
|||
}
|
||||
out.writeInt(source.length);
|
||||
out.write(source);
|
||||
out.writeFloat(queryBoost);
|
||||
out.writeInt(types.length);
|
||||
for (String type : types) {
|
||||
out.writeUTF(type);
|
||||
|
|
|
@ -66,7 +66,7 @@ public class SearchContext implements Releasable {
|
|||
|
||||
private final TimeValue timeout;
|
||||
|
||||
private final float queryBoost;
|
||||
private float queryBoost = 1.0f;
|
||||
|
||||
|
||||
private Scroll scroll;
|
||||
|
@ -100,12 +100,11 @@ public class SearchContext implements Releasable {
|
|||
|
||||
private volatile Timeout keepAliveTimeout;
|
||||
|
||||
public SearchContext(long id, SearchShardTarget shardTarget, TimeValue timeout, float queryBoost, byte[] source,
|
||||
public SearchContext(long id, SearchShardTarget shardTarget, TimeValue timeout, byte[] source,
|
||||
String[] types, Engine.Searcher engineSearcher, IndexService indexService) {
|
||||
this.id = id;
|
||||
this.shardTarget = shardTarget;
|
||||
this.timeout = timeout;
|
||||
this.queryBoost = queryBoost;
|
||||
this.source = source;
|
||||
this.types = types;
|
||||
this.engineSearcher = engineSearcher;
|
||||
|
@ -150,6 +149,11 @@ public class SearchContext implements Releasable {
|
|||
return queryBoost;
|
||||
}
|
||||
|
||||
public SearchContext queryBoost(float queryBoost) {
|
||||
this.queryBoost = queryBoost;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Scroll scroll() {
|
||||
return this.scroll;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search 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.elasticsearch.search.query;
|
||||
|
||||
import org.codehaus.jackson.JsonParser;
|
||||
import org.codehaus.jackson.JsonToken;
|
||||
import org.elasticsearch.search.SearchParseElement;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* {
|
||||
* queryBoost : {
|
||||
* "index1" : 1.4,
|
||||
* "index2" : 1.5
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class QueryBoostParseElement implements SearchParseElement {
|
||||
|
||||
@Override public void parse(JsonParser jp, SearchContext context) throws Exception {
|
||||
JsonToken token;
|
||||
while ((token = jp.nextToken()) != JsonToken.END_OBJECT) {
|
||||
if (token == JsonToken.FIELD_NAME) {
|
||||
String indexName = jp.getCurrentName();
|
||||
if (indexName.equals(context.shardTarget().index())) {
|
||||
jp.nextToken(); // move to the value
|
||||
// we found our query boost
|
||||
context.queryBoost(jp.getFloatValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,7 +33,6 @@ public class QueryParseElement implements SearchParseElement {
|
|||
@Override public void parse(JsonParser jp, SearchContext context) throws Exception {
|
||||
JsonIndexQueryParser indexQueryParser = (JsonIndexQueryParser) context.queryParser();
|
||||
Query query = indexQueryParser.parse(jp);
|
||||
query.setBoost(query.getBoost() * context.queryBoost());
|
||||
context.query(query);
|
||||
}
|
||||
}
|
|
@ -46,12 +46,18 @@ public class QueryPhase implements SearchPhase {
|
|||
ImmutableMap.Builder<String, SearchParseElement> parseElements = ImmutableMap.builder();
|
||||
parseElements.put("from", new FromParseElement()).put("size", new SizeParseElement())
|
||||
.put("queryParserName", new QueryParserNameParseElement())
|
||||
.put("queryBoost", new QueryBoostParseElement())
|
||||
.put("query", new QueryParseElement())
|
||||
.put("sort", new SortParseElement())
|
||||
.putAll(facetsPhase.parseElements());
|
||||
return parseElements.build();
|
||||
}
|
||||
|
||||
@Override public void preProcess(SearchContext context) {
|
||||
context.query().setBoost(context.query().getBoost() * context.queryBoost());
|
||||
facetsPhase.preProcess(context);
|
||||
}
|
||||
|
||||
public void execute(SearchContext searchContext) throws QueryPhaseExecutionException {
|
||||
try {
|
||||
searchContext.queryResult().from(searchContext.from());
|
||||
|
|
|
@ -106,7 +106,7 @@ public class TwoInstanceEmbeddedSearchTests extends AbstractServersTests {
|
|||
@Test public void testDfsQueryFetch() throws Exception {
|
||||
SearchSourceBuilder sourceBuilder = searchSource()
|
||||
.query(termQuery("multi", "test"))
|
||||
.from(0).size(60).explain(true);
|
||||
.from(0).size(60).explain(true).indexBoost("test", 1.0f).indexBoost("test2", 2.0f);
|
||||
|
||||
List<DfsSearchResult> dfsResults = newArrayList();
|
||||
for (ShardsIterator shardsIt : indicesService.searchShards(clusterService.state(), new String[]{"test"}, null)) {
|
||||
|
|
Loading…
Reference in New Issue