Skip to content

Commit

Permalink
All Field: Automatically detect when field level boosting is used, an…
Browse files Browse the repository at this point in the history
…d optimize when its not, closes elastic#2189.
  • Loading branch information
kimchy committed Aug 20, 2012
1 parent d885e5c commit 7f5b8fc
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 6 deletions.
Expand Up @@ -79,6 +79,10 @@ public void addText(String name, String text, float boost) {
entries.add(entry);
}

public boolean customBoost() {
return customBoost;
}

public void clear() {
this.entries.clear();
this.current = null;
Expand Down
Expand Up @@ -24,6 +24,7 @@
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.lucene.all.AllField;
Expand Down Expand Up @@ -67,6 +68,9 @@ public static class Builder extends AbstractFieldMapper.Builder<Builder, AllFiel

private boolean enabled = Defaults.ENABLED;

// an internal flag, automatically set if we encounter boosting
boolean autoBoost = false;

public Builder() {
super(Defaults.NAME);
builder = this;
Expand Down Expand Up @@ -101,7 +105,7 @@ protected Builder searchAnalyzer(NamedAnalyzer searchAnalyzer) {
@Override
public AllFieldMapper build(BuilderContext context) {
return new AllFieldMapper(name, store, termVector, omitNorms, omitTermFreqAndPositions,
indexAnalyzer, searchAnalyzer, enabled);
indexAnalyzer, searchAnalyzer, enabled, autoBoost);
}
}

Expand All @@ -115,6 +119,8 @@ public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext
Object fieldNode = entry.getValue();
if (fieldName.equals("enabled")) {
builder.enabled(nodeBooleanValue(fieldNode));
} else if (fieldName.equals("auto_boost")) {
builder.autoBoost = nodeBooleanValue(fieldNode);
}
}
return builder;
Expand All @@ -123,16 +129,24 @@ public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext


private boolean enabled;
// The autoBoost flag is automatically set based on indexed docs on the mappings
// if a doc is indexed with a specific boost value and part of _all, it is automatically
// set to true. This allows to optimize (automatically, which we like) for the common case
// where fields don't usually have boost associated with them, and we don't need to use the
// special SpanTermQuery to look at payloads
private volatile boolean autoBoost;

public AllFieldMapper() {
this(Defaults.NAME, Defaults.STORE, Defaults.TERM_VECTOR, Defaults.OMIT_NORMS, Defaults.OMIT_TERM_FREQ_AND_POSITIONS, null, null, Defaults.ENABLED);
this(Defaults.NAME, Defaults.STORE, Defaults.TERM_VECTOR, Defaults.OMIT_NORMS, Defaults.OMIT_TERM_FREQ_AND_POSITIONS, null, null, Defaults.ENABLED, false);
}

protected AllFieldMapper(String name, Field.Store store, Field.TermVector termVector, boolean omitNorms, boolean omitTermFreqAndPositions,
NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer, boolean enabled) {
NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer, boolean enabled, boolean autoBoost) {
super(new Names(name, name, name, name), Field.Index.ANALYZED, store, termVector, 1.0f, omitNorms, omitTermFreqAndPositions,
indexAnalyzer, searchAnalyzer);
this.enabled = enabled;
this.autoBoost = autoBoost;

}

public boolean enabled() {
Expand All @@ -141,12 +155,15 @@ public boolean enabled() {

@Override
public Query queryStringTermQuery(Term term) {
if (!autoBoost) {
return new TermQuery(term);
}
return new AllTermQuery(term);
}

@Override
public Query fieldQuery(String value, QueryParseContext context) {
return new AllTermQuery(names().createIndexNameTerm(value));
return queryStringTermQuery(names().createIndexNameTerm(value));
}

@Override
Expand Down Expand Up @@ -180,6 +197,13 @@ protected Fieldable parseCreateField(ParseContext context) throws IOException {
// reset the entries
context.allEntries().reset();

// if the autoBoost flag is not set, and we indexed a doc with custom boost, make
// sure to update the flag, and notify mappings on change
if (!autoBoost && context.allEntries().customBoost()) {
autoBoost = true;
context.setMappingsModified();
}

Analyzer analyzer = findAnalyzer(context);
return new AllField(names.indexName(), store, termVector, context.allEntries(), analyzer);
}
Expand Down Expand Up @@ -234,6 +258,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
if (enabled != Defaults.ENABLED) {
builder.field("enabled", enabled);
}
if (autoBoost != false) {
builder.field("auto_boost", autoBoost);
}
if (store != Defaults.STORE) {
builder.field("store", store.name().toLowerCase());
}
Expand Down
Expand Up @@ -20,12 +20,16 @@
package org.elasticsearch.test.unit.index.mapper.all;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.lucene.all.AllEntries;
import org.elasticsearch.common.lucene.all.AllField;
import org.elasticsearch.common.lucene.all.AllTokenStream;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.test.unit.index.mapper.MapperTests;
import org.hamcrest.Matchers;
import org.testng.annotations.Test;

import static org.elasticsearch.common.io.Streams.copyToBytesFromClasspath;
Expand Down Expand Up @@ -53,6 +57,22 @@ public void testSimpleAllMappers() throws Exception {
assertThat(allEntries.fields().contains("simple1"), equalTo(true));
}

@Test
public void testAllMappersNoBoost() throws Exception {
String mapping = copyToStringFromClasspath("/org/elasticsearch/test/unit/index/mapper/all/noboost-mapping.json");
DocumentMapper docMapper = MapperTests.newParser().parse(mapping);
byte[] json = copyToBytesFromClasspath("/org/elasticsearch/test/unit/index/mapper/all/test1.json");
Document doc = docMapper.parse(new BytesArray(json)).rootDoc();
AllField field = (AllField) doc.getFieldable("_all");
AllEntries allEntries = ((AllTokenStream) field.tokenStreamValue()).allEntries();
assertThat(allEntries.fields().size(), equalTo(3));
assertThat(allEntries.fields().contains("address.last.location"), equalTo(true));
assertThat(allEntries.fields().contains("name.last"), equalTo(true));
assertThat(allEntries.fields().contains("simple1"), equalTo(true));
FieldMapper mapper = docMapper.mappers().smartNameFieldMapper("_all");
assertThat(mapper.queryStringTermQuery(new Term("_all", "foobar")), Matchers.instanceOf(TermQuery.class));
}

@Test
public void testSimpleAllMappersWithReparse() throws Exception {
String mapping = copyToStringFromClasspath("/org/elasticsearch/test/unit/index/mapper/all/mapping.json");
Expand Down
Expand Up @@ -15,7 +15,8 @@
},
"last":{
"type":"string",
"index":"not_analyzed"
"index":"not_analyzed",
"boost":2.0
}
}
},
Expand Down
@@ -0,0 +1,55 @@
{
"person":{
"_all":{
"enabled":true
},
"properties":{
"name":{
"type":"object",
"dynamic":false,
"properties":{
"first":{
"type":"string",
"store":"yes",
"include_in_all":false
},
"last":{
"type":"string",
"index":"not_analyzed"
}
}
},
"address":{
"type":"object",
"include_in_all":false,
"properties":{
"first":{
"properties":{
"location":{
"type":"string",
"store":"yes",
"index_name":"firstLocation"
}
}
},
"last":{
"properties":{
"location":{
"type":"string",
"include_in_all":true
}
}
}
}
},
"simple1":{
"type":"long",
"include_in_all":true
},
"simple2":{
"type":"long",
"include_in_all":false
}
}
}
}
Expand Up @@ -16,7 +16,8 @@
},
"last":{
"type":"string",
"index":"not_analyzed"
"index":"not_analyzed",
"boost":2.0
}
}
},
Expand Down

0 comments on commit 7f5b8fc

Please sign in to comment.