Chris Hinshaw
Chris Hinshaw

Reputation: 7255

Hibernate Search is it possible or recommended to do keywork search on specific collection

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;

}

Upvotes: 0

Views: 375

Answers (1)

RandomMooCow
RandomMooCow

Reputation: 734

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.

Upvotes: 2

Related Questions