Sorting on BigDecimals not alphanumeric

When getting my search results, the sort order for a BigDecimal field is alphanumeric, what leads to a unwanted order in the frontend:

What do I have to do to get a correct sorting (the currency symbol is appended by the frontend though).

Can you help me please?

You’re on Hibernate Search 5, right?

In Hibernate Search 5, BigDecimals are stored as text by default, which will lead to something like this.

There is better support for BigDecimals in Hibernate Search 6, which will automatically convert the BigDecimal in a dedicated format with a configurable scale. So you won’t have this problem in Hibernate Search 6.
But if you didn’t upgrade, you must have a reason.

In Hibernate Search 5, you will have to use a custom bridge to convert your BigDecimals to long before indexing. There is an example of such a bridge in the reference documentation. The example just below shows how to apply the bridge to your field.
You will also need to make the field sortable, and you cannot do this with @SortableField if you’re using a custom bridge. See this example for more information.

Again, you wouldn’t need all this custom code with Hibernate Search 6; this would be enough:

@ScaledNumberField(decimalScale = 2, sortable = Sortable.YES)
private BigDecimal amount;

I understand that I cannot use the @SortableField annotation. But what instead? Or do you mean , just remove it?

Sorry, as long as version 6 is not officially released, I cannot use it…

I tried to follow you examples. I first added a custom bridge:

class BigDecimalNumericFieldBridge : TwoWayFieldBridge {
    override fun set(name: String, value: Any, document: Document, luceneOptions: LuceneOptions) {
        if (value != null) {
            val decimalValue = value as BigDecimal
            val indexedValue = decimalValue.multiply(storeFactor).toLong()
            luceneOptions.addNumericFieldToDocument(name, indexedValue, document)
        }
    }

    override fun get(name: String, document: Document): Any {
        val fromLucene = document[name]
        val storedBigDecimal = BigDecimal(fromLucene)
        return storedBigDecimal.divide(storeFactor)
    }

    override fun objectToString(`object`: Any): String {
        return `object`.toString()
    }

    companion object {
        private val storeFactor = BigDecimal.valueOf(100)
    }
}

than I remove the annotation Sortable Field from the class, instead i added FieldBridge

    @NotNull
    @Field
    @FieldBridge(impl = BigDecimalNumericFieldBridge::class)
    var salesPrice: BigDecimal = BigDecimal.ZERO

But after rebuilding the index and restarting the application, I now get this error:

org.hibernate.search.exception.SearchException: HSEARCH000301: Requested sort field(s) salesPrice are not configured for entity type com.....persistence.entities.warehouse.Article mapped to index articles_index, thus an uninverting reader must be created. 
You should declare the missing sort fields using @SortableField.

So what’s going wrong now?

Remove it, and add some bits to your bridge implementation, as I suggested:

These are the important bits in the example I linked:

implements MetadataProvidingFieldBridge
      document.addSortedDocValuesFieldToDocument( name + "_firstName", firstName );
  @Override
  public void configureFieldMetadata(String name, FieldMetadataBuilder builder) {
      builder
          .field( name + "_firstName", FieldType.STRING )
              .sortable( true )

this does not work for me as the API does not offer that function you mentioned

Hmm, there’s a problem in the documentation, I’ll fix that. Try this:

luceneOptions.addNumericDocValuesFieldToDocument(name, indexedValue, document)

i changed this, but when running the app it throws this error:

unexpected docvalues type NUMERIC for field 'salesPrice' (expected=SORTED). Use UninvertingReader or index with docvalues

Alright. Hopefully this will be the last attempt… try this instead of luceneOptions.addNumericDocValuesFieldToDocument:

document.add(new SortedNumericDocValuesField(name, indexedValue));

still gettint

 unexpected docvalues type SORTED_NUMERIC for field 'salesPrice' (expected=SORTED). Use UninvertingReader or index with docvalues.

crashes whenever i do

qb.sort().byField(*myFieldName*.property, SortField.Type.STRING).asc().createSort()

and having no idea how to fix this :frowning:

It’s not a string field, though, why are you passing SortField.Type.STRING?

If you’re using a recent version (5.11), you shouldn’t even need to pass the field type:

Hello yrodiere,

now finally I have made it. The last adjustment that was necessary was this one:

document.add(NumericDocValuesField(name, indexedValue))

instead of

document.add(SortedNumericDocValuesField(name, indexedValue))

Thanks for your patience and the helpful code examples!

1 Like