Bridge not called for null values in Hibernate Search 6

Not sure is it a bug or new desired behaviour, but comparing to Hibernate Search 5, new Hibernate Search 6 does not call bridge when property value is null.

The problem is that I want some code to run if certain properties are null and now I’m not able to do it anymore.

Here is my Manufacturer property inside Article entity:

@Entity @Indexed
class Article {
    // ID and more
    // ...
    @ManyToOne( fetch = FetchType.LAZY )
    @FullTextField(
        projectable = Projectable.NO,
        searchable  = Searchable.YES,
        valueBridge = @ValueBridgeRef( type = ManufacturerBridge.class )
    )
    private Manufacturer manufacturer;
    // ...
}

While indexing when Manufacturer is not null, my bridge injects some keywords like Man_302 which means “Manufacturer with ID 302”; then it injects Man_Status_Enabled if Manufacturer is enabled in user interface or Man_Status_Disabled, Man_Status_Hidden, Man_Status_Banned and so on.

When Manufacturer is null, my bridge injects keyword Man_Not_Set into manufacturer field of Article so that later I could have query to select all articles which has enabled manufacturer or manufacturer is not set:

(manufacturer:Man_St_Enabled   manufacturer:Man_Not_Set)~1

That gives me chance to have Article with unknown Manufacturer but still include it into search queries.
Now that bridge is not called anymore for null values, I have no chance to inject Man_Not_Set and my manufacturer field stays empty in Lucene index.

Is there a chance to change this behaviour to bring bridge call back on null values?
Should I remove my property bridge and move my logic to class bridge? I would prefer it to be property bridge because it’s more readable but if there is no other way, I’d move it despite the logic.

P.S. Just for the record, here is the full Lucene query when searching Articles for word “Split”:

+(
	+(
		+(
			(
				(name:split)^20.0
				(shortName:split)^20.0
				(description:split)^2.0
				(searchAid:split)^7.5
				(manufacturer:split)^2.5
				(priceInfos:split)^2.5
				(categories:split)^5.0
				(tags:split)^3.0
			)~1
		)
	)
	+visibility:Art_Visible
	+objectStatus:ENABLED
	+( (manufacturer:man_st_enabled  manufacturer:man_not_set)~1 )
)

That’s right.

IMO you should use a boolean field + a string field for that. But you do you.

Note that’s not strictly necessary in Hibernate Search 6 since you can use the exists predicate, e.g. in Hibernate Search 6.1:

f.bool()
        .should( f.match().field("manufacturer").matching("foo") )
        .should( f.matchAll().except( f.exists().field( "manufacturer" ) )

Or (much clearer IMO) in Hibernate Search 6.2:

f.or(
        f.match().field("manufacturer").matching("foo") )
        f.not( f.exists().field( "manufacturer" ) )
)

If you really want to insert Man_Not_set in your index, consider using @KeywordField + indexNullAs (since analysis really doesn’t look necessary in this case):

@Entity @Indexed
class Article {
    // ID and more
    // ...
    @ManyToOne( fetch = FetchType.LAZY )
    @KeywordField(
        projectable = Projectable.NO,
        searchable  = Searchable.YES,
        indexNullAs = "Man_Not_set",
        valueBridge = @ValueBridgeRef( type = ManufacturerBridge.class )
    )
    private Manufacturer manufacturer;
    // ...
}

You’re not using a PropertyBridge, you’re using a ValueBridge. ValueBridge is simpler to implement and works with @*Field annotations, while PropertyBridge is more complex and requires custom annotations, but is more flexible. See Hibernate Search 6.2.2.Final: Reference Documentation

If the solutions above are not an option, you could move to PropertyBridge.

1 Like

Un-deleting and adding more information from private messages (with @horvoje’s approval) in case others have this problem.