Repository navigation
Let Elasticsearch sort by Byte and Short keys - #5081
Conversation
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
3 open findings
The PR description (and the method signature) indicates the returned string type should depend on… · New This test’s setup and comment state it runs 'Without allow-mapping-update', and later asserts the… · Newidxis closed only on the happy-path; if an assertion fails (e.g., mapping unexpectedly includes… · New
What changed in this PR
Fix Elasticsearch/OpenSearch sorting failures when ordering by Byte, Short, or unmapped string keys by ensuring unmapped_type is set to a valid ES datatype.
Changes:
- Update
ElasticSearchIndex.convertToEsDataTypeto returnbyte,short, andkeywordinstead ofnull/stringfor relevant key types. - Add regression tests covering mixed-index ordering by
Byte/Shortand ordering by an unmapped string field under external dynamic mappings. - Document the behavior change in the changelog.
| File | Description |
|---|---|
| janusgraph-es/src/main/java/org/janusgraph/diskstorage/es/ElasticSearchIndex.java | Fixes ES unmapped_type derivation for Byte/Short and modernizes string type to keyword. |
| janusgraph-es/src/test/java/org/janusgraph/diskstorage/es/ElasticsearchConfigTest.java | Adds regression test ensuring ordering works when the index has no mapping for a string key. |
| janusgraph-backend-testutils/src/main/java/org/janusgraph/graphdb/JanusGraphIndexTest.java | Adds mixed-index regression test for ordering by Byte and Short keys. |
| docs/changelog.md | Documents the fix and relevant Elasticsearch version behavior. |
🧠 Review effort: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
b5e5bb5 to
5b3bb3f
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
3 open findings
Using a fixedstoreNameincreases the risk of cross-test interference (e.g., when test execution… · New If an exception is thrown byregister(...)oradd(...), the firstIndexTransactionwill… · New Nit: the new method header comment is hard to scan (very long lines) and is missing a space after… · New
3 resolved since last review
🧠 Review effort: Lite
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
3 open findings
The new comment implies the return value matches whatpushMappingmaps a sortable string field… · New Using a fixedstoreNamecan make this test brittle if the suite reuses the same Elasticsearch… · New Minor style issue: add a space after//to match typical Java comment formatting (e.g., `//… · New
3 resolved since last review
🧠 Review effort: Lite
Fixes JanusGraph#5080 ElasticSearchIndex gives each sort the unmapped_type of its key, the type which Elasticsearch sorts by where an index has no mapping of the field. It had none for a Byte or a Short key and sent null, which Elasticsearch and OpenSearch reject with a 400, so a graph query or an index query ordered by such a key failed. It now gives byte and short, the types which JanusGraph maps such keys to. For a string key it gave string, which Elasticsearch 5 replaced with text and keyword: where the index had no mapping of the key, as under an external dynamic mapping before any document held it, Elasticsearch 8 and 9 rejected the sort, and Elasticsearch 6 and 7 sorted by keyword in its place, with a deprecation warning. It now gives keyword. Signed-off-by: Oleksandr Porunov <alexandr.porunov@gmail.com> Co-authored-by: Oleksandr Porunov <alexandr.porunov@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
5b3bb3f to
b4e973d
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
2 open findings
3 resolved since last review
🧠 Review effort: Lite



Fixes #5080
A graph query which a mixed index on Elasticsearch answered in the order of a
Byteor aShortkey failed withCould not call index, and an index query ordered by such a key failed too:ElasticSearchIndexgave the sort anunmapped_typeof null, which Elasticsearch and OpenSearch reject with a 400 ([field_sort] unmapped_type doesn't support values of type: VALUE_NULL), asconvertToEsDataTypehad no type for these keys. This PR givesbyteandshort, the types whichpushMappingmaps them to. It also giveskeywordin place ofstringfor a string key, a type which Elasticsearch 5 replaced: Elasticsearch 8 and 9 rejected such a sort where the index had no mapping of the key.Changes
ElasticSearchIndex.convertToEsDataType, which gives theunmapped_typeof a sort by a key, the type which Elasticsearch sorts by where an index has no mapping of the field:shortfor aShortkey andbytefor aBytekey, the types whichpushMappingmaps them to. It returned null for them, and the request went out with"unmapped_type": null, which Elasticsearch rejects while it parses the request, whether the field is mapped or not;keywordfor every string key. Anunmapped_typeapplies only to an index without a mapping of the field, whose documents all sort as having no value, so it needs only a type which Elasticsearch can sort strings by, whatever the key's mapping:pushMappingmaps the field which such a sort reads askeyword, or astextwhere the key has a custom string analyzer. It gavestring, which Elasticsearch 5 replaced withtextandkeyword: where the index had no mapping of the field, Elasticsearch 8 and 9 rejected the sort (No mapper found for type [string]), and Elasticsearch 6 and 7 sorted bykeywordin its place, with a deprecation warning,[unmapped_type:string] should be replaced with [unmapped_type:keyword].Of the built-in types which
ElasticSearchIndexsupports, every one now has an unmapped type, with the PR which compares UUIDs as their string forms (branchorder-uuids-as-the-indexes-do): it adds a branch for a UUID key,keyword, after theGeoshapeone. The two merge cleanly in either order.What the versions accept, sending the sorts by hand to a container of each, with an index which maps a keyword, a byte and a short field, and a field which it doesn't map:
unmapped_typeof the sortnullbyte,short,keywordstring, mapped fieldstring, unmapped fieldNo mapper found for type [string]No mapper found for type [string]The 400 for
nullis[field_sort] unmapped_type doesn't support values of type: VALUE_NULL, for a mapped field as for an unmapped one.Tests
JanusGraphIndexTest.testMixedIndexOrdersByBytesAndShorts(every index backend; the mixed index is namedmixed, which the Solr test container has a collection for). A mixed index ontag, aBytekeysmalland aShortkeymedium; four vertices with the least value of each, 0, the greatest and -1. For each of the two keys, the graph queryg.V().has('tag', 't').order().by(key)comes in the order of the values, ascending, descending and ascending with a limit of two, and so does the index queryindexQuery('mixed', 'v.tag:t').orderBy(key, desc).ElasticsearchConfigTest.testOrderByStringKeyWhichTheIndexHasNotMapped. Under an external dynamic mapping (index.[X].elasticsearch.create.use-external-mappings) withoutindex.[X].elasticsearch.create.allow-mapping-update, a string key registered with the index, and a document without it: the index has no mapping of the key, which the test checks, and a query ordered by the key returns the document.Without the fix, on Elasticsearch 9.5.4:
byteandshortcases:testMixedIndexOrdersByBytesAndShortsfails at its first query ordered bysmall, withCould not call indexfrom the 400 for theunmapped_typeof null.shortcase alone: it fails at the first query ordered bymedium, after those bysmallpassed.stringfor a string key:testOrderByStringKeyWhichTheIndexHasNotMappedfails withPermanentBackendException: Unknown exception while executing index operation, from the 400No mapper found for type [string]. Elasticsearch 6 and 7 and OpenSearch acceptstringfor a field without a mapping (see the table above), so there the test passes either way.Runs, locally, Java 11, on master
dd4f0f845:BerkeleyElasticsearchTest(118, 1 skipped),ElasticsearchIndexTest(306) andElasticsearchConfigTest(13) pass against Elasticsearch 9.5.4 in a container, with checkstyle./solr/admin/collectionswhile it starts), soBerkeleySolrTest's configuration ran in the JVM against aMiniSolrCloudCluster(Solr 9.10.1) with the test schema:testMixedIndexOrdersByBytesAndShortspasses. The rest of the Solr suite is left to CI.Notes
Numberother than the six built-in ones:ElasticSearchIndexsupports it, butpushMappingmaps it to no type, so a sort by it still goes out with anunmapped_typeof null. Any numeric type would do there, as it only applies where no document of the index holds the field; it is left to a change which maps such types.Characterkeys, whichElasticSearchIndexdoesn't support.string, andkeywordas well.🤖 Generated with Claude Code