RelationEmbeddingBinder.java
package com.taxonomy.search;
import com.taxonomy.catalog.model.TaxonomyRelation;
import org.hibernate.search.engine.backend.document.DocumentElement;
import org.hibernate.search.engine.backend.document.IndexFieldReference;
import org.hibernate.search.mapper.pojo.bridge.TypeBridge;
import org.hibernate.search.mapper.pojo.bridge.binding.TypeBindingContext;
import org.hibernate.search.mapper.pojo.bridge.mapping.programmatic.TypeBinder;
import org.hibernate.search.mapper.pojo.bridge.runtime.TypeBridgeWriteContext;
/**
* Hibernate Search {@link TypeBinder} that computes a DJL/ONNX embedding vector for
* a {@link TaxonomyRelation} and writes it to an {@code "embedding"} {@code @VectorField}.
*
* <p>The enriched text is formed as:
* {@code "{sourceName} {relationType} {targetName}. {description}"}
*
* <p>Graceful degradation: when the DJL model is unavailable the bridge writes nothing.
*/
public class RelationEmbeddingBinder implements TypeBinder {
@Override
public void bind(TypeBindingContext context) {
context.dependencies()
.use("relationType")
.use("description")
.use("sourceNode.nameEn")
.use("targetNode.nameEn");
IndexFieldReference<float[]> embeddingField =
EmbeddingBridgeSupport.createEmbeddingField(context);
context.bridge(TaxonomyRelation.class, new Bridge(embeddingField));
}
public static final class Bridge implements TypeBridge<TaxonomyRelation> {
private final IndexFieldReference<float[]> embeddingField;
Bridge(IndexFieldReference<float[]> embeddingField) {
this.embeddingField = embeddingField;
}
@Override
public void write(DocumentElement target, TaxonomyRelation relation,
TypeBridgeWriteContext context) {
EmbeddingBridgeSupport.writeEmbedding(target, embeddingField, relation,
Bridge::buildEnrichedText);
}
public static String buildEnrichedText(TaxonomyRelation relation) {
String sourceName = (relation.getSourceNode() != null
&& relation.getSourceNode().getNameEn() != null)
? relation.getSourceNode().getNameEn() : "";
String targetName = (relation.getTargetNode() != null
&& relation.getTargetNode().getNameEn() != null)
? relation.getTargetNode().getNameEn() : "";
String relType = relation.getRelationType() != null
? relation.getRelationType().name().toLowerCase().replace('_', ' ') : "";
StringBuilder sb = new StringBuilder();
sb.append(sourceName).append(" ").append(relType).append(" ").append(targetName);
if (relation.getDescription() != null && !relation.getDescription().isBlank()) {
sb.append(". ").append(relation.getDescription());
}
return sb.toString().trim();
}
}
}