0

I am trying to do what seems like a simple search query but am unable to find out if there is a way and if so is it efficient.

I am currently using hibernate with hibernate search 4.3.0. What I am trying to do is to search a specific collection. For example I have an Inventory class that contains a List of InventoryItem. I would like to perform a keyword search where only the items in a specific inventory are searched. Is it possible to limit the search to a specific. Both the Inventory and InventoryItem class extends DatastoreObject which has a @Id Long id field as it's primary key.

Inventory Class

/**
 * Inventory is a container of inventory objects.
 * 
 * @author chinshaw
 */
@Entity
@Indexed
public class Inventory extends DatastoreObject {

    @Size(min = 5, max = 256, message = "inventory name must be between 5 and 256 characters")
    @Column(length = 256)
    @Field
    private String name;

    @Size(max = 512, message = "inventory description cannot exceed 512 characters")
    @Column(length = 512)
    @Field
    private String description;

    /**
     * List of all inventory items in this object.
     */
    @IndexedEmbedded
    @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
    private List<InventoryItem> inventoryItems = new ArrayList<InventoryItem>();
...

My InventoryItem Class

/**
 * 
 * @author chinshaw
 */
@Entity
@Indexed
public class InventoryItem extends DatastoreObject implements IHasImage {

    /**
     * String manufacturer's serial number.
     */
    private String sin;

    /**
     * This is the name of the item.
     */
    @NotNull
    @Field
    private String name;

    /**
     * This is the text description of the object.
     */
    @Size(max = 200, message = "description must be less than 200 characters")
    @Field
    private String description;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "inventory_id")
    private Inventory inventory;

...

Example code of what I am currently trying

public List<InventoryItem> searchItems(Long inventoryId, String searchContext) {

    FullTextEntityManager session = Search.getFullTextEntityManager(getEntityManager());
    EntityTransaction tx = session.getTransaction();



    QueryBuilder qb = session.getSearchFactory().buildQueryBuilder().forEntity(InventoryItem.class).get();

    // How do I limit the search to only contain the inventoryId.
    org.apache.lucene.search.Query searchQuery = qb.keyword().onFields("title", "description").matching(searchContext).createQuery();
    javax.persistence.Query query  = session.createFullTextQuery(searchQuery, InventoryItem.class);

    // execute search
    List<InventoryItem> items = query.getResultList();

    tx.commit();

    return items;

}
Chris Hinshaw
  • 6,967
  • 2
  • 39
  • 65

1 Answers1

2

You should be able to do this with the bool() method on QueryBuilder. For instance, to filter the returned InventoryItems such that they must belong to the Inventory with ID inventoryId, you can use:

org.apache.lucene.search.Query searchQuery = qb.bool()
    .must(qb.keyword().onFields("title", "description").matching(searchContext).createQuery())
    .must(qb.keyword().onField("inventory.id").matching(inventoryId).createQuery())
    .createQuery();

This will create an AND condition between your search on the title/description of the InventoryItems and the ID of the Inventory you want matched.

Note, however, that you must annotate InventoryItem.inventory as @IndexedEmbedded for it to be included in InventoryItem's index.

RandomMooCow
  • 734
  • 9
  • 23
  • Excellent answer!! I had to some refactoring of my entity ownership's to get it to work. One last question though, do you know of a way that I could possibly get this to work with the owning side of the relationship being in the Inventory class. To get it to work I had to change to using the mappedBy so that the inventoryItem is the owning side of the relationship. I was hoping I could leave it as a @OneToMany without the mapped by. This is not a deal breaker but it seems more natural that the Inventory class would own the InventoryItem in the entity relationship. Thanks again for your help. – Chris Hinshaw Jul 23 '13 at 15:26
  • 1
    Your new configuration sounds correct. As far as I understand, you want the owning side to be InventoryItem, even though it may not make sense conceptually. For a better explanation, see this answer: http://stackoverflow.com/a/2749719/1260254. – RandomMooCow Jul 23 '13 at 17:32