Visualize the db structure or data

Hello folks,

I’m using Spring with Hibernate ORM and Hibernate Search 6.2.3.Final. I’ve configured my entities for indexing using annotations like @IndexedEmbedded and @IndexingDependency. However, I’m encountering warnings from Hibernate Search about missing related entities. It seems like there’s a problem with how I’ve set up the indexing for entities with relationships.

At this point, I need to visualize the database structure along with its data to pinpoint which entities are causing the issue. Is there a way to view the database relationships or the data itself through Hibernate Search? Thanks for any help!

Hey, thanks for reaching out.

Usually, Hibernate Search warnings and errors should give enough information to pinpoint the problem. What warnings are you getting?

As for visualising the database, there are external tools you can try, or maybe your IDE can do that for you.

Dear @mbekhta,

@Indexed
@Entity
public class PR {
    public Long id;
    public String description;

    @JsonIgnore
    @ManyToOne(fetch = FetchType.EAGER)
    @IndexedEmbedded
    @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
    private P p;

    public P getP() {
        return p;
    }
}


@Indexed
@Entity
public class Corporation extends PR {
    public Long personelCount;
    public LocalDate openningDate;

    @JsonIgnore
    @Transient
    public Organization getOrganization() {
        return (Organization) super.getP();
    }
}


@Indexed
@Entity
public class P {
    public Long id;

    @FullTextField()
    private String code;

}


@Indexed
@Entity
public class Organization extends P implements Tr {
    @OneToOne
    public OrganizationGeneralInfo generalInfo;
}


public interface Tr<D> {
    @JsonIgnore
    Collection<D> getTrs();

    @JsonIgnore
    default D getTr() {
        Collection<D> trs = getTr();
    }
}

@Indexed
@MappedSuperclass
public abstract class BaseT<T extends Tr> {
    @NotNull
    @FullTextField(highlightable = Highlightable.ANY)
    public String name;

}


My entities are structured similar to the code examples above. I’ve made efforts to ensure clarity and understandability. However, when I conduct a full-text search using the field ‘corporation.organization.getTranslation.name,’ Hibernate Search alerts me with the warning ‘HSEARCH000610: Unknown field ‘corporation.organization.getTranslation.name.’’

The confusion arises, because I’m actually searching within the field ‘corporation.organization.code.’ Despite this, I still receive the same error message: 'HSEARCH000610: Unknown field 'corporation.organization.code

I understood i mistake an error while indexing to Organization entity. I thought to myself that if I could see the database created by the hibernate search library, the data kept inside and the relationship between them, I could see exactly where I made a mistake.
Maybe I’m going the wrong way, but this was the first thing that came to my mind, because I thought that if I could see how and in what way the hibernate search library stores the data, I would actually have a little information about which entities are indexed and in what way.

Even if it is not related to this error, I would be very grateful if you could tell me if there is a tool or plugin that shows the database and data created by the hibernate search library. In addition, it would be greatly appreciated if you could provide information about indexing at this stage, thank you.

Ohh, ok, got it. So it’s not about the relational database but about the indexes and their structure.

For that, you may be interested in Inspecting the mapping. In particular, look at the example Accessing the index metamodel. You can inspect the model and see what index structure you have. If you are unsure what fields you have you can just place a break point in your IDE and inspect what you have in runtime.

If you are using the Elasticsearch backend, you can also export the schema and then inspect the generated JSON files to see the index structure.

With that said… looking at the example you’ve shared:

SearchResult<?> result = searchSession.search( Corporation.class )
		.where( f -> f.match()
				.field( "p.code" )
				.matching( "something" ) )
		.fetch( 20 );

Something like this should work. Since the @IndexedEmbedded is placed on a property p that’s the name it will be linked to in the index. getOrganization() getter is not “known” to Hibernate Search since it does not have any Hibernate Search annotations on it. And if you search for Corporations then there’s no need to start with the corporation. prefix. the field path required by the search predicates starts with a property of the object you are searching, see this section about field paths if you’d need more information.

1 Like

thanks @mbekhta, I’ve realized my mistake; you are right about the prefix approach. Additionally, I’ve made updates to the structure in the post above.

Here are the steps I took:

I modified the prefix to be “organization.translations.name”.
I added two annotations to the getOrganization() method.

    ...
    ...
    @IndexedEmbedded
    @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.NO, derivedFrom = @ObjectPath(@PropertyValue(propertyName = "organization")))
    @JsonIgnore
    @Transient
    public Organization getOrganization() {
    ...
    ...

After implementing these changes, I can now retrieve data using “organization.translations.name”. However, I encountered an issue: while I can retrieve data using this format, I’m unable to fetch updated data when the name is changed. Interestingly, reindexing all data after updating the name allows me to access the updated value.

The problem seems to stem from the reindexOnUpdate = ReindexOnUpdate.NO annotation. When I attempt to change this to reindexOnUpdate = ReindexOnUpdate.SHALLOW, Hibernate Search throws an error.

According to my research in the Hibernate Search documentation, I should add an @AssociationInverseSide(…) implementation. However, even after adding this annotation, I still encounter errors. I’m uncertain about the correct way to implement @AssociationInverseSide. Could you provide some guidance on this?

Thanks for your assistance.

P.S. I found a post from someone who faced a similar issue, although not exactly the same:

@Indexed
@Entity
public class PR {
    public Long id;
    public String description;

    @JsonIgnore
    @ManyToOne(fetch = FetchType.EAGER)
    @IndexedEmbedded
    @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
    private P p;

    public P getP() {
        return p;
    }
}


@Indexed
@Entity
public class Corporation extends PR {
    public Long personelCount;
    public LocalDate openningDate;

    @JsonIgnore
    @Transient
    @IndexedEmbedded
    @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.NO, derivedFrom = @ObjectPath(@PropertyValue(propertyName = "organization")))
    public Organization getOrganization() {
        return (Organization) super.getP();
    }
}


@Indexed
@Entity
public class P {
    public Long id;

    @FullTextField()
    private String code;

}


@Indexed
@Entity
public class Organization extends P implements Tr {
    @IndexedEmbedded
    @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
    @OneToMany(mappedBy = "owner", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    public Set<OrganizationGeneralInfo> translations = new HashSet<>();
}

public class OrganizationGeneralInfo {
    @FullTextField(highlightable = Highlightable.ANY)
    private String formalName;

    @FullTextField()
    private String name;
}

public interface Tr<D> {
    @JsonIgnore
    Collection<D> getTrs();

    @JsonIgnore
    default D getTr() {
        Collection<D> trs = getTr();
    }
}

@Indexed
@MappedSuperclass
public abstract class BaseT<T extends Tr> {
    @NotNull
    @FullTextField(highlightable = Highlightable.ANY)
    public String name;

}

Hey, glad to hear you’ve been able to address some of the problems.

I see that in the mapping you’ve shared both p and getOrganization() have the mapping annotations. That means that the index will have two different properties in it ( p, organization).

I’m unable to fetch updated data when the name is changed. Interestingly, reindexing all data after updating the name allows me to access the updated value.

That’s expected since ReindexOnUpdate.NO will not update Corporation when Organization is changed. And similar with ReindexOnUpdate.SHALLOW – if the name of Organization is updated and not just a different Organization is set, then there’s no update:

changing an association — adding or removing associated elements, i.e. “shallow” updates — should trigger reindexing of the object on which the change happened, but changing properties of associated entities — “deep” updates — should not.

See Limiting reindexing of containing entities with @IndexingDependency

If you want to use the @AssociationInverseSide, then that means that the inverse side must exist in the mapping i.e.:

public class Corporation {
    // note that derived from should be something that is related to the ORM mapping rather than just some getter:
    @IndexingDependency(derivedFrom = @ObjectPath(@PropertyValue(propertyName = "p")))
    @AssociationInverseSide(inversePath = @ObjectPath({
            @PropertyValue(propertyName = "corporations")
    }))
    public Organization getOrganization();
}

public class Organization {
    // have a collection of corpopartions that this organization is linked to
    // so that when the organization is updated it can tell Hibernate Search
    // which corporations have to be reindexed.
    // Or maybe it's a 1-1 association, but you get the idea, there should be some association
    // on this side of the mapping

    @OneToMany(mappedBy = "organization")
    Set<Corporation> corporations;
}

See this example for how @AssociationInverseSide is used.