We need to add support for fields of type {{Long}}, {{java.util.Date}} and {{Boolean}}, both in the backends (Elasticsearch + Lucene) and the mapper (POJO mapper).
"Support" here means:
* Allow to map properties of these types in the POJO mapper, thanks to default value bridges. * Allow to map identifiers of these types ( Date and Long only , probably not it doesn't make much sense for Date and Boolean) in the POJO mapper, thanks to default identifier bridges. * Allow to declare index fields of these types in indexes * Allow to create predicates on fields of these types ("match" and "range" predicates, mainly) * Allow to create sorts on fields of these types * Allow to project on fields of these types
You can use the existing code for similar types to help you. For example there is already support for {{Integer}} (similar to Long) and there is already support for {{LocalDate}} (similar to {{Date}}).
On the mapper side, it should be rather easy. You need to:
* add test methods to {{org.hibernate.search.integrationtest.mapper.pojo.mapping.definition.DocumentIdDefaultBridgeIT}} for each newly supported type and {{Long}} its primitive counterpart (if any) , {{long}} ; use {{boxedInteger}} and {{primitiveInteger}} as examples. The tests should initially fail. Note that the test for {{LocalDate}} is missing, maybe take this opportunity to add it? * add test methods to {{org.hibernate.search.integrationtest.mapper.pojo.mapping.definition.FieldDefaultBridgeIT}} for each newly supported type and its primitive counterpart (if any); use {{boxedInteger}} and {{primitiveInteger}} as examples. The tests should initially fail. * add and implementation of {{IdentifierBridge}} for {{Long}} next to {{org.hibernate.search.mapper.pojo.bridge.builtin.impl.DefaultIntegerIdentifierBridge}}. Note that the implementation for {{LocalDate}} is missing, maybe take this opportunity to add it? * register the new identifier bridge implementations implementation in the {{org.hibernate.search.mapper.pojo.bridge.impl.BridgeResolver}} constructor * register pass-through value bridges for each type (long, date, boolean) in the {{org.hibernate.search.mapper.pojo.bridge.impl.BridgeResolver}} constructor
And voilà! The tests should now pass. Note these tests use a mock instead of a real backend, so that's only the beginning.
The backend side will be a bit more complex. I recommend first doING everything for {{Long}} (tests, indexing, predicates, sorts, projections), and only when it works correctly, have a look at the other types.
First, the tests . See these classes:
* {{org.hibernate.search.integrationtest.backend.tck.search.predicate.MatchSearchPredicateIT}} for the "match" predicate; you should only need to add an entry to the list returned by {{org.hibernate.search.integrationtest.backend.tck.search.predicate.MatchSearchPredicateIT.IndexMapping#mapSupportedFields}} * {{org.hibernate.search.integrationtest.backend.tck.search.predicate.RangeSearchPredicateIT}} for the "range" predicate; you should only need to add an entry to the list returned by {{org.hibernate.search.integrationtest.backend.tck.search.predicate.RangeSearchPredicateIT.IndexMapping#mapSupportedFields}} or directly to {{org.hibernate.search.integrationtest.backend.tck.search.predicate.RangeSearchPredicateIT.IndexMapping#unsupportedFieldModels}} * {{org.hibernate.search.integrationtest.backend.tck.search.sort.SearchSortByFieldIT}} for sorts, add an entry to {{org.hibernate.search.integrationtest.backend.tck.search.sort.SearchSortByFieldIT#mapSupportedFields}} or {{org.hibernate.search.integrationtest.backend.tck.search.sort.SearchSortByFieldIT#mapUnsupportedFields}} * {{org.hibernate.search.integrationtest.backend.tck.search.projection.SearchProjectionIT}} for projections, add an entry to {{org.hibernate.search.integrationtest.backend.tck.search.projection.SearchProjectionIT#mapSupportedFields}}
After that, all these tests should fail. Which is good!
Note that in order to run the tests from the IDE, you will have to execute {{org.hibernate.search.integrationtest.backend.lucene.util.LuceneTckTestRunner}} or {{org.hibernate.search.integrationtest.backend.elasticsearch.util.ElasticsearchTckTestRunner}} (adjust the classname filter as necessary, but please don't commit the filter change). For Elasticsearch, you'll need a running ES instance; see https://github.com/Sanne/elasticsearch-light-testing.
Then, the Elasticsearch implementation. You will need to:
* Create a new "codec", which is the class that converts the "Hibernate Search" type ({{Long}} in this case) to the backend-specific type (a {{JsonElement}} for Elasticsearch). Have a look at org.hibernate.search.backend.elasticsearch.types.codec.impl.IntegerFieldCodec, copy-paste it as "LongFieldCodec" and adapt it as necessary. * Create a new "Index schema field context", which implements the DSL presented to the user and to the mapper when adding a field to the index. Have a look at {{org.hibernate.search.backend.elasticsearch.types.dsl.impl.ElasticsearchIntegerIndexSchemaFieldContextImpl}}, copy/paste it as "ElasticsearchLongIndexSchemaFieldContextImpl" and adapt it as necessary. * Instantiate this new context from an {{asLong}} method in {{org.hibernate.search.backend.elasticsearch.document.model.dsl.impl.ElasticsearchIndexSchemaFieldContextImpl}} (the method should be defined in the implemented interface, {{org.hibernate.search.engine.backend.document.model.dsl.IndexSchemaFieldContext}}). Do not forget to update the {{org.hibernate.search.backend.elasticsearch.document.model.dsl.impl.ElasticsearchIndexSchemaFieldContextImpl#as}} method to delegate to {{asLong}} when the given type is {{Long.class}}.
This should do the trick for Elasticsearch.
Lucene should be fairly similar, except that you will additionally have to create one class per field type for each of the following:
* the "match predicate builder", "range predicate builder, and "field predicate builder factory" which creates these builders. For example the factory for type integer will not be the same as for longs, because in Lucene, querying a Long field is done differently than querying an Integer field. See {{org.hibernate.search.backend.lucene.types.predicate.impl.IntegerFieldPredicateBuilderFactory}} for an example. * the "field sort builder" and "field sort builder factory" which creates this builder. See {{org.hibernate.search.backend.lucene.types.sort.impl.IntegerFieldSortBuilderFactory}} for an example.
Then you will have to reference these types from the "Index schema field context", in the "contribute" method.
About java.util.Date:
* In the Elasticsearch backend, you will have to format the date to String before sending it to the cluster. See how it's done for {{LocalDate}} to get an idea of what I mean: {{org.hibernate.search.backend.elasticsearch.types.dsl.impl.ElasticsearchLocalDateIndexSchemaFieldContextImpl}} * In the Lucene backend, you will have to convert the Date to an epoch in a specific converter. See how it's done for {{LocalDate}}: {{org.hibernate.search.backend.lucene.types.converter.impl.LocalDateFieldConverter}}
About boolean:
* Booleans can hardly be ordered, so you will have to disable range predicates and sorts on boolean fields. This essentially means you will need a specific "field predicate builder factory" and "field projection builder factory"; see how it's done for {{GeoPoint}}.
---
Initial ticket description:
The goal is to cover one type of each category: * Numeric scalars (Integer + Long) * Java 8 Date/time (LocalDate) * java.util.Date * String * GeoPoint * Enums * Boolean
This means in particular supporting:
* Predicates (match, range, ...) * Sorts * Projections * Default value bridges |
|