@ValueBinderRef not called when retrieving value from elastic search

Hi everyone,

I discovered that my indexed value in elastic search is not preprocessed when retrieved by hibernate search through the valueBinder I defined. Here the binder :

@Transient
@GenericField(name = SearchableParapheurIndexed.DATE_SIGNATURE,
			valueBinder = @ValueBinderRef(type = DateValueBinder.class))
@IndexingDependency(derivedFrom = {....})
public Date getParapheurDateSignature() {
//return a Date
}

and the binder :

public class DateValueBinder implements ValueBinder {

    @Override
    public void bind(ValueBindingContext<?> context) {
        context.bridge(
                Date.class,
                new DateValueBridge(),
                context.typeFactory().asInstant().projectable(Projectable.YES).sortable(Sortable.YES)
        );
    }
}

and the bridge :

public class DateValueBridge implements ValueBridge<Date, Instant> {

    @Override
    public Instant toIndexedValue(Date value, ValueBridgeToIndexedValueContext context) {
        return IndexerPreProcessor.processDateSetAtUTCTimezone(value);
    }

    @Override
    public Date fromIndexedValue(Instant value, ValueBridgeFromIndexedValueContext context) {
        return IndexerPreProcessor.processDateGetAtDefaultTimezone(value);
    }

    /**
     * for multi index search it is necessary
     * @param other
     * @return
     */
    public boolean isCompatibleWith(ValueBridge<?, ?> other) {
        return other instanceof DateValueBridge;
    }
}

I do a query on the index (depot-000001 index) and then retrieve documents. But this “Date” value is not pre-processed by the binder, so in the retrieved documents, the date is wrong. Of course, if I manually apply the method “fromIndexedValue” in debug mode, the retrieved date is ok. But in debug mode, hibernate search should stop into this method for each document retrieved, isn’t it ? This is not the case. I certainly miss something.
Note : on the contrary, when mass indexing, the binder is well called. The stored value in elastic search has been preprocessed.
Thanks.

Could you please show the code that does this?

By default, Hibernate Search returns managed Hibernate ORM entities, loaded from the database. Entities loaded from database are loaded by Hibernate ORM, so the Hibernate Search bridges are not involved in that case.

fromIndexedValue is only called when the value is retrieved from the index, as its name suggests. So it’s only called when using a field projection.

By default, Hibernate Search returns managed Hibernate ORM entities, loaded from the database

I don’t understand, if I have empty indexes, I have no hits, no ORM entities. It returns documents.

Could you please show the code that does this?

The query does not involve this field, but results in retrieving one or more documents. I see them when I query directly my ES server. But the documents retrieved by HSearch is not the one I read in the response when requesting directly ES server with JSON (missing the preprocessed of the date by hsearch).

I need to force a field projection ?

The projection is done when retrieving the _source from ES response (in bold) :

ElasticsearchSearchQueryOptionsStep<PROJECTION, SearchLoadingOptionsStep> optionsStep = searchSession
                .search(targetIndexes)
                .extension(ElasticsearchExtension.get())
                .select(f -> f.composite(
                        (source, hits, score) -> {
                            JsonElement jsonValue = getJsonDiscriminatorValue(source);
                            if (jsonValue != null) {
                                AbstractESBuilder<CONF, PROJECTION> b = getESBuilder(jsonValue.getAsString());
                                Class<PROJECTION> compositeClazz = b.getCompositeClazzFromSource(source);
                                **PROJECTION compositeResult = b.fromJson(source, compositeClazz);**

}

Thanks.

It’s my turn not to understand. What documents do you want to return from an empty index?

Anyway, you’re using projections, so that’s irrelevant.

There, you have it. The source projection returns the JSON exactly as it was provided by Elasticsearch, and that’s on purpose.

Bridges are not applied there, because we don’t want to: this projection returns the _source unaltered. Even if we wanted to apply bridges, we could not: the Date/Instant types used in your bridge don’t mean anything in JSON, where strings are used instead.

If you want Hibernate Search and its bridges to be applied, don’t use the source projection which bypasses Hibernate Search; use the field projection instead.

Nice, that’s clearer. Using the source projection, I need to manually apply the “fromIndexedValue” then. It is a pity, but it works. I’am not the author of using the source projection, but there is certainly a reason, probably to do JSON response post process.

Thank you.