Search code examples
hibernateelasticsearchhibernate-search

Hibernate Search: mapping IndexedEmbedded on ElasticSearch causes No field found for [] in mapping


I've two entities, Search and Amount that I'm mapping using Hibernate Search in this way:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
@Entity
@Indexed
public class Search extends SearchableItem {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEARCH_SEQ")
    @DocumentId
    private Long id;

    @Embedded
    @Valid
    @IndexedEmbedded
    private Amount maxAmount;
    
    @Embedded
    @Valid
    @IndexedEmbedded
    private Amount minAmount;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
@Embeddable
public class Amount {

    @NotNull
    @ScaledNumberField(sortable = Sortable.YES)
    private BigDecimal value;
    
    @NotNull
    @Enumerated(EnumType.STRING)
    @GenericField
    private CurrencyCode currency;

}

These annotations creates my index in this way on Elasticsearch:

{
    "search-000001": {
        "aliases": {
            "search-read": {
                "is_write_index": false
            },
            "search-write": {
                "is_write_index": true
            }
        },
        "mappings": {
            "dynamic": "strict",
            "properties": {
                "_entity_type": {
                    "type": "keyword",
                    "index": false
                },
                "maxAmount": {
                    "dynamic": "strict",
                    "properties": {
                        "currency": {
                            "type": "keyword",
                            "doc_values": false
                        },
                        "value": {
                            "type": "scaled_float",
                            "scaling_factor": 100
                        }
                    }
                },
                "minAmount": {
                    "dynamic": "strict",
                    "properties": {
                        "currency": {
                            "type": "keyword",
                            "doc_values": false
                        },
                        "value": {
                            "type": "scaled_float",
                            "scaling_factor": 100
                        }
                    }
                }
            }
        },
        "settings": {
            "index": {
                "routing": {
                    "allocation": {
                        "include": {
                            "_tier_preference": "data_content"
                        }
                    }
                },
                "number_of_shards": "1",
                "provided_name": "search-000001",
                "creation_date": "1644485712235",
                "analysis": {
                    "normalizer": {
                        "sort": {
                            "filter": [
                                "asciifolding",
                                "lowercase"
                            ],
                            "type": "custom"
                        }
                    },
                    "analyzer": {
                        "name": {
                            "filter": [
                                "asciifolding",
                                "lowercase"
                            ],
                            "type": "custom",
                            "tokenizer": "standard"
                        },
                        "generic_text": {
                            "filter": [
                                "asciifolding",
                                "lowercase",
                                "porter_stem"
                            ],
                            "type": "custom",
                            "tokenizer": "standard"
                        }
                    }
                },
                "number_of_replicas": "1",
                "uuid": "GBfV36PLT2-JEVPlbE2DVw",
                "version": {
                    "created": "7160399"
                }
            }
        }
    }
}

For the search on Elasticsearch, I'm using a custom score function which try to access to minAmount and maxAmount objects inside the search document, but I receive this error:

Unhandled Exception illegal_argument_exception

No field found for [maxAmount] in mapping

Stack:
[
  "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:100)",
  "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:28)",
  "score += calculateScoreAmount(doc.maxAmount, doc.minAmount, params);\n  ",
  "                                 ^---- HERE"
]

I had the same problem in the past on other entities and I solved it specifying @GenericField(sortable = Sortable.YES) on the property that I needed to access in the score script (please note that without the explicit Sortable.YES I received the error from Elasticsearch during the script score function execution). The problem here is that Amount is a custom defined object and @GenericField(sortable = Sortable.YES) cannot be specified on it.
Can someone help on this?


Solution

  • maxAmount is an object field. It does not make sense to retrieve its value through doc.maxAmount, because this syntax is for accessing doc values, and object fields are not represented in doc values.

    I'm not sure what your script is or where you are passing it to Elasticsearch, but the problem is probably there.

    If you want to access the docvalues of maxAmount.value/minAmount.value, then you should probably replace calculateScoreAmount(doc.maxAmount, doc.minAmount, params); with calculateScoreAmount(doc['maxAmount.value'].value, doc['minAmount.value'].value, params);

    If you want to access the JSON object representing maxAmount/minAmount, then you should not use docvalues but the _source: calculateScoreAmount(ctx._source.maxAmount, ctx._source.minAmount, params);. I'm not sure this syntax is exactly right, since I couldn't find any documentation to access the source in a sort, but it should be close to this. Also, keep in mind that this will be slow if you have lots of documents.

    See also: