Allow sorting on nested sub generated field

When you have a nested document and want to sort on its fields, it's perfectly doable on regular fields but not on "generated" sub fields.

Here is a SENSE recreation:

```
DELETE /tmp

PUT /tmp

PUT /tmp/doc/_mapping
{
  "properties": {
    "flat": {
      "type": "string",
      "index": "analyzed",
      "fields": {
        "sub": {
          "type": "string",
          "index": "not_analyzed"
        }
      }
    },
    "nested": {
      "type": "nested",
      "properties": {
        "foo": {
          "type": "string",
          "index": "analyzed",
          "fields": {
            "sub": {
              "type": "string",
              "index": "not_analyzed"
            }
          }
        }
      }
    }
  }
}

PUT /tmp/doc/1
{
  "flat":"bar",
  "nested":{
    "foo":"bar"
  }
}
```

When sorting on `flat.sub` sub field, everything is fine:

```
GET /tmp/doc/_search
{
  "sort": [
    {
      "flat.sub": {
        "order": "desc"
      }
    }
  ]
}

```

When sorting on `nested` field, everything is fine:

```
GET /tmp/doc/_search
{
  "sort": [
    {
      "nested.foo": {
        "order": "desc"
      }
    }
  ]
}

```

But when sorting on `nested.sub` field, sorting is incorrect:

```
GET /tmp/doc/_search
{
  "sort": [
    {
      "nested.foo.sub": {
        "order": "desc"
      }
    }
  ]
}

Closes #6150.
This commit is contained in:
David Pilato 2014-05-13 15:56:06 +02:00
parent 08e57890f8
commit e0a95d9c19
2 changed files with 76 additions and 1 deletions

View File

@ -828,7 +828,8 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
String objectPath = fieldName.substring(0, indexOf);
ObjectMappers objectMappers = objectMapper(objectPath);
if (objectMappers == null) {
return null;
indexOf = objectPath.lastIndexOf('.');
continue;
}
if (objectMappers.hasNested()) {

View File

@ -28,6 +28,7 @@ import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.common.text.StringAndBytesText;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
@ -50,6 +51,7 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.scriptFunction;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.*;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
import static org.hamcrest.Matchers.*;
@ -1506,4 +1508,76 @@ public class SimpleSortTests extends ElasticsearchIntegrationTest {
}
}
/**
* Test case for issue 6150: https://github.com/elasticsearch/elasticsearch/issues/6150
*/
@Test
public void testNestedSort() throws ElasticsearchException, IOException, InterruptedException, ExecutionException {
assertAcked(prepareCreate("test")
.addMapping("type",
XContentFactory.jsonBuilder()
.startObject()
.startObject("type")
.startObject("properties")
.startObject("nested")
.field("type", "nested")
.startObject("properties")
.startObject("foo")
.field("type", "string")
.startObject("fields")
.startObject("sub")
.field("type", "string")
.field("index", "not_analyzed")
.endObject()
.endObject()
.endObject()
.endObject()
.endObject()
.endObject()
.endObject()
.endObject()));
ensureGreen();
client().prepareIndex("test", "type", "1").setSource(jsonBuilder().startObject()
.startObject("nested")
.field("foo", "bar bar")
.endObject()
.endObject()).execute().actionGet();
refresh();
// We sort on nested field
SearchResponse searchResponse = client().prepareSearch()
.setQuery(matchAllQuery())
.addSort("nested.foo", SortOrder.DESC)
.execute().actionGet();
assertNoFailures(searchResponse);
SearchHit[] hits = searchResponse.getHits().hits();
for (int i = 0; i < hits.length; ++i) {
assertThat(hits[i].getSortValues().length, is(1));
Object o = hits[i].getSortValues()[0];
assertThat(o, notNullValue());
assertThat(o instanceof StringAndBytesText, is(true));
StringAndBytesText text = (StringAndBytesText) o;
assertThat(text.string(), is("bar"));
}
// We sort on nested sub field
searchResponse = client().prepareSearch()
.setQuery(matchAllQuery())
.addSort("nested.foo.sub", SortOrder.DESC)
.execute().actionGet();
assertNoFailures(searchResponse);
hits = searchResponse.getHits().hits();
for (int i = 0; i < hits.length; ++i) {
assertThat(hits[i].getSortValues().length, is(1));
Object o = hits[i].getSortValues()[0];
assertThat(o, notNullValue());
assertThat(o instanceof StringAndBytesText, is(true));
StringAndBytesText text = (StringAndBytesText) o;
assertThat(text.string(), is("bar bar"));
}
}
}