Going back to the previous example from hibernate where we have the following entities (Book, Author, Review). Let's say we want to group the books by author, how should we achieve that?
- Annotate Author.id with @facet.
@Facets({ @Facet, @Facet(name = "id_facet", forField = "id_for_facet", encoding = FacetEncodingType.STRING) })
@Fields({
@Field(name = "id_for_facet", analyze = Analyze.NO, bridge = @FieldBridge(impl = org.hibernate.search.bridge.builtin.IntegerBridge.class)) })
@Id
@Column(name = "id")
@GeneratedValue
private Integer id; - Create a class that will hold the desired entity and the facet result.
public class EntityFacet
implements Facet {
private final Facet delegate;
private final T entity;
public EntityFacet(Facet delegate, T entity) {
this.delegate = delegate;
this.entity = entity;
}
@Override
public String getFacetingName() {
return delegate.getFacetingName();
}
@Override
public String getFieldName() {
return delegate.getFieldName();
}
@Override
public String getValue() {
return delegate.getValue();
}
@Override
public int getCount() {
return delegate.getCount();
}
@Override
public Query getFacetQuery() {
return delegate.getFacetQuery();
}
public T getEntity() {
return entity;
}
@Override
public String toString() {
return "EntityFacet [delegate=" + delegate + ", entity=" + entity + "]";
}
} - Let's query the facet and the entity that contains more of the information we want. In this case the author. Note that we need to add the faceted field in the includePaths property in the @IndexedEmbedded annotation of the main entity (Book), or don't specify a field so all annotated fields are included.
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Book.class).get();
org.apache.lucene.search.Query luceneQuery = qb.all().createQuery();
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(luceneQuery, Book.class);
// define the facet
FacetingRequest authorFacet = qb.facet().name("authorIdFacet").onField("authors.id_facet").discrete()
.orderedBy(FacetSortOrder.COUNT_DESC).includeZeroCounts(false).maxFacetCount(5).createFacetingRequest();
// retrieve facet manager and apply faceting request
FacetManager facetManager = fullTextQuery.getFacetManager();
facetManager.enableFaceting(authorFacet);
// retrieve the faceting results
List<Facet> facets = facetManager.getFacets("authorIdFacet");
// collect all the ids
List<Integer> vcIds = facets.stream().map(p -> Integer.parseInt(p.getValue())).collect(Collectors.toList());
// query all the Authors given the id we faceted above, I think multiLoad has
// been introduced in HS 5.x
List<Author> authors = fullTextEntityManager.unwrap(Session.class).byMultipleIds(Author.class).multiLoad(vcIds);
// fill our container object with the facet and author entity
List<EntityFacet<Author>> entityFacets = new ArrayList<>(facets.size());
for (int i = 0; i < facets.size(); i++) {
entityFacets.add(new EntityFacet<Author>(facets.get(i), authors.get(i)));
}
entityFacets.stream().forEach(System.out::println);
For code reference you may check this repository: https://github.com/czetsuya/hibernate-search-demo
Got a question? Don't hesitate to ask :-)
0 nhận xét:
Đăng nhận xét