Reputation: 115
Is it possible to sort elasticsearch documents conditionally? The condition is quite clear, it is visible in my script. When somefield value is present I want to sort by some collection of fields, otherwise, different collection of fields. Fields has different types (strings, numbers). And I would like to sort numbers as numbers (not as strings) so that when sorting ascending this would be correct order (providing that field1 is string and field2 is number).
Taking only field1 and field2, field3 is empty:
ASC: (A is first part so goes to the top, then numbers are sorted)
doc1: AA 2
doc2: H 1
doc3: H 2
DESC:
doc1: H 2
doc2: H 1
doc3: AA 2
When we add other documents, with fields field4-field7 we should have
ASC:
H 1 (doc with field1 and field2)
H 2 (doc with field1 and field2)
1 X 25/2024 (doc with fields4-7)
12 AR 25/2024 (doc with fields4-7)
I use spring-data-elasticsearch:
Script script = new Script("myscriptcontent ");
ScriptSortBuilder order = SortBuilders.scriptSort(script, ScriptSortBuilder.ScriptSortType.NUMBER)
.order(direction.isAscending() ? SortOrder.ASC : SortOrder.DESC);
return nativeSearchQueryBuilder.withSort(order).build();
The ScriptSortBuilder
requires scriptsorttype to be present, however there can be only String and Number, which may not fit here .. Is it possible to build such query with spring-data-elasticsearch ?
The query sort part that I can seen in logs:
{
"_script" : {
"script" : {
"source" : "if (doc['somefield.keyword'].size() > 0) { return [doc['field1.keyword'].value, doc['field2.keyword'].value, doc['field3.keyword'].value]; } else { return [doc['field4.keyword'].value, doc['field5.keyword'].value, doc['field6.keyword'].value, doc['field6.keyword'].value]; } ",
"lang" : "painless"
},
"type" : "number",
"order" : "desc"
}
}
The effect is this exception:
Suppressed: org.elasticsearch.client.ResponseException: method [POST], host [http://localhost:9200], URI [/myindex/_search?typed_keys=true&max_concurrent_shard_requests=5&search_type=query_then_fetch&batched_reduce_size=512], status line [HTTP/1.1 400 Bad Request]
{"error":{"root_cause":[{"type":"script_exception","reason":"compile error","script_stack":["... d'].size() > 0) { return [doc['field1.k ..."," ^---- HERE"],"script":"if (doc['somefield.keyword'].size() > 0) { return [doc['field1.keyword'].value, doc['field2.keyword'].value, doc['field3.keyword'].value]; } else { return [doc['field4.keyword'].value, doc['field5.keyword'].value, doc['field6.keyword'].value, doc['field7.keyword'].value]; } ","lang":"painless","position":{"offset":56,"start":31,"end":81}}],"type":"search_phase_execution_exception","reason":"all shards failed","phase":"query","grouped":true,"failed_shards":[{"shard":0,"index":"rt","node":"xZy_xw9-R0e-JSfMIeyzBg","reason":{"type":"script_exception","reason":"compile error","script_stack":["... d'].size() > 0) { return [doc['field1.k ..."," ^---- HERE"],"script":"if (doc['somefield.keyword'].size() > 0) { return [doc['field1.keyword'].value, doc['field2.keyword'].value, doc['field3.keyword'].value]; } else { return [doc['field4.keyword'].value, doc['field5.keyword'].value, doc['field6.keyword'].value, doc['field7.keyword'].value]; } ","lang":"painless","position":{"offset":56,"start":31,"end":81},"caused_by":{"type":"class_cast_exception","reason":"Cannot cast from [java.util.ArrayList] to [double]."}}}]},"status":400}
..............
3.0.0.war//org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:2171)
... 153 more
Upvotes: 0
Views: 143
Reputation: 19471
You are using a native query (NativeSearchQuery, that is from the previous version of Spring Data Elasticsearch using the deprecated RestHighLEvelCLient
) and native query can and must be used when Spring Data Elasticsearch cannot produce the desired queries, scripts etc. So the answer is no. Spring Data Elasticsearch cannot do that.
Upvotes: 0