# PropertyBinder to create additional Lucene field

**URL:** <https://discourse.hibernate.org/t/propertybinder-to-create-additional-lucene-field/7141>\
**Category:** Hibernate Search\
**Created:** [January 13, 2023, 4:32pm UTC](https://discourse.hibernate.org/t/propertybinder-to-create-additional-lucene-field/7141 "2023-01-13T16:32:44Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![horvoje](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/horvoje/32/779_2.png) [@horvoje](https://discourse.hibernate.org/u/horvoje)\
**Post date:** [January 13, 2023, 4:32pm UTC](https://discourse.hibernate.org/t/propertybinder-to-create-additional-lucene-field/7141/1 "2023-01-13T16:32:44Z")

</div>

Trying to migrate to Hibernate Search 6.

The idea is to have `enum` class indexed to be able to filter out by `enum` name and also to create additional `Integer` field in Lucene to have sort ability.

The goal is to get 2 fields in Lucene index:

1. `importance` (`Text`, searchable, containing `enum` item name (“LOW”, “HIGH”…)
2. `importance_numeric` (`Numeric`, sortablem, containing score from `enum` item)?

Which type of bridge shoud I use?  
What type of @\*Field to put on `Importance` property inside `Article`?

  

```auto
@AllArgsConstructor @Getter 
enum Importance {
	  FIRST(3),
	    TOP(2),
	   HIGH(1),
	 NORMAL(0),
	   LOW(-1),
	BOTTOM(-2),
	  LAST(-3);
	private final int score;
}

```

  

**Enum is used inside `Article` class:**

```auto
@Entity @Indexed 
class Article {

	 // ...

	@Enumerated(EnumType.STRING)
	@Field(
		index = Index.YES,
		analyze = Analyze.NO,
		store = Store.NO,
		bridge = @FieldBridge(impl = ImportanceBridge.class)
	)
	@SortableField
	private Importance importance = Importance.NORMAL;

	 // ...

}

```

  

**Bridge from Hibernate Search 5 was pretty simple:**

```auto
class ImportanceBridge implements MetadataProvidingFieldBridge {

	@Override
	public void configureFieldMetadata(
		String name,
		FieldMetadataBuilder builder
	) {
		builder.field(name + "_numeric", FieldType.INTEGER).sortable(true);
	}

	@Override
	public void set(
		String name, Object object, Document document,
		LuceneOptions luceneOptions
	) {
		if (!(object instanceof Importance)) {
			return;
		}
		Importance i = (Importance) object;
		int score = i.getScore();
		luceneOptions.addNumericFieldToDocument(
			name + "_numeric", Integer.valueOf(score), document
		);
		document.add(new NumericDocValuesField(name + "_numeric", score));
	}
}

```

  

**Tried to create this as `PropertyBinder` but I got lost.**

```auto
class ImportanceBridge implements PropertyBinder {

	private static final String PROPERTY_NAME = "importance";
	private static final String SUFFIX = "_numeric";

	@Override
	public void bind(PropertyBindingContext context) {

		context.dependencies().use(PROPERTY_NAME);

		IndexSchemaObjectField importanceNumericField =
			context.indexSchemaElement().objectField(PROPERTY_NAME + SUFFIX);

	//	-- don't know what to do with this :(
	//	IndexFieldType<Integer> importanceNumericFieldType =
	// context.typeFactory().asInteger().toIndexFieldType();

		context.bridge(Importance.class, new ImportancePropertyBridge(
			importanceNumericField.toReference()
		));
	}

	private static class ImportancePropertyBridge
			implements PropertyBridge<Importance> {

		private final IndexObjectFieldReference importanceFieldReference;

		private ImportancePropertyBridge(
			IndexObjectFieldReference importanceFieldReference
		) {
			this.importanceFieldReference = importanceFieldReference;
		}

		@Override
		public void write(
			DocumentElement target, Importance bridgedElement,
			PropertyBridgeWriteContext context
		) {
			Integer intValue = Integer.valueOf(bridgedElement.getScore());
			target.addObject( this.importanceFieldReference );

			// ????? what next?

        }

    }

}

```

---

<div class="post-metadata">

**Author:** ![horvoje](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/horvoje/32/779_2.png) [@horvoje](https://discourse.hibernate.org/u/horvoje)\
**Post date:** [January 14, 2023, 10:39am UTC](https://discourse.hibernate.org/t/propertybinder-to-create-additional-lucene-field/7141/2 "2023-01-14T10:39:22Z")

</div>

Is that the way to do it?

```auto
@Entity @Indexed 
class Article {

	 // ...

	@GenericField(
		projectable = Projectable.NO,
		searchable = Searchable.YES,
		sortable = Sortable.NO
	)
	@GenericField(
		projectable = Projectable.NO,
		searchable = Searchable.NO,
		sortable = Sortable.YES,
		name="importance_numeric",
		valueBridge = @ValueBridgeRef(type = ImportanceBridge.class)
	)
	@Enumerated(EnumType.STRING)
	private Importance importance = Importance.NORMAL;

	 // ...

}

```

* * *

```auto
public class ImportanceBridge implements ValueBridge<Importance, Integer> {

	@Override
	public Integer toIndexedValue(
		Importance value,
		ValueBridgeToIndexedValueContext context
	) {
		if (value == null) {
			log.warn("{} Importance should not be NULL", LOG_PREFIX);
			throw new IllegalStateException("Importance should not be NULL");
		}
		return Integer.valueOf(value.getScore());
	}

}

```

---

<div class="post-metadata">

**Author:** ![yrodiere](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/yrodiere/32/1760_2.png) [@yrodiere](https://discourse.hibernate.org/u/yrodiere)\
**Post date:** [January 16, 2023, 7:43am UTC](https://discourse.hibernate.org/t/propertybinder-to-create-additional-lucene-field/7141/3 "2023-01-16T07:43:58Z")

</div>

> [@horvoje](#):
>
> Is that the way to do it?

Yes that’s one solution.

If you want to use only one annotation, you can do this instead:

```auto
// NOTE: this is a binder, not a bridge.
class ImportanceBinder implements PropertyBinder {

	@Override
	public void bind(PropertyBindingContext context) {

		// This bridge is applied to properties of enum type, and that type is immutable.
		// Thus we don't need to declare precise dependencies.
		context.dependencies().useRootOnly();

		context.bridge(Importance.class, new ImportancePropertyBridge(
			context.indexSchemaElement()
					.field(context.bridgedElement().name(), f -> f.asString())
					.toReference(),
			context.indexSchemaElement()
					.field(context.bridgedElement().name() + "_numeric", f -> f.asInteger()
							.searchable(Searchable.NO).sortable(Sortable.YES))
					.toReference()
		));
	}

	private static class ImportancePropertyBridge
			implements PropertyBridge<Importance> {

		private final IndexFieldReference<String> stringField;
		private final IndexFieldReference<Integer> integerField;

		private ImportancePropertyBridge(
			IndexFieldReference<String> stringField,
			IndexFieldReference<Integer> integerField
		) {
			this.stringField = stringField;
			this.integerField = integerField;
		}

		@Override
		public void write(
			DocumentElement target, Importance bridgedElement,
			PropertyBridgeWriteContext context
		) {
			target.addValue( stringField, bridgedElement.name() );
			target.addValue( integerField, bridgedElement.getScore() );
		}
    }

}

```

```java
@Entity @Indexed 
class Article {

	 // ...

	@PropertyBinding(binder = @PropertyBinderRef(type = ImportanceBinder.class))
	@Enumerated(EnumType.STRING)
	private Importance importance = Importance.NORMAL;

	 // ...

}

```

See also [`PropertyBinder`](https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#mapper-orm-bridge-propertybridge-basics), [Declaring fields](https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#mapper-orm-bridge-index-field-dsl-basics), [Declaring field types](https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#mapper-orm-bridge-index-field-type-dsl).

---

<div class="post-metadata">

**Author:** ![horvoje](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/horvoje/32/779_2.png) [@horvoje](https://discourse.hibernate.org/u/horvoje)\
**Post date:** [January 16, 2023, 5:51pm UTC](https://discourse.hibernate.org/t/propertybinder-to-create-additional-lucene-field/7141/4 "2023-01-16T17:51:15Z")

</div>

Thank you very much!
