I am just getting started with Hibernate Search and I am attempting to index the following domain model. In this model, we have a product which has a one-to-many relationship with a list of descriptions which are language-specific and a one-to-many relationship with a list of SKU identifiers for the product.
Is it possible through Hibernate Search to obtain a distinct list of products where:
* description is in english and contains a specific word and the sku is a specific value
* description contains a specific word
* sku is or contains a specific term
* sku contains specific term and is of a specific sku type
When I built a test query on my domain structure where I tried to find products that had specific type of skus with a term which I knew didn't exist in the relational data, it still returned a hit.
Code:
// create builder
QueryBuilder builder = ftEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Product.class).get();
// create query
// query matches where productId is 1 where sku is a SUPPLIER sku with value 1234567890
// this combination does not exist in the product_skus table
// but product does have SUPPLIER sku with 00ABCD and a VENDOR sku with 1234567890
Query query = builder.bool()
.must(builder.keyword().onField("productId").matching(1L).createQuery())
.must(builder.keyword().onField("skus.type").matching(SKU.TYPE_SUPPLIER).createQuery())
.must(builder.phrase().onField("skus.sku").matching("1234567890").createQuery())
.createQuery();
FullTextQuery ftQuery = ftEntityManager.createFullTextQuery(query, Product.class);
// returns 1 but should return 0.
System.out.println("Hits: " + ftQuery.getResultSize());
The above code generates this Lucene query:
+productId:1 +skus.type:1 +skus.sku:1234567890I know some special types of join queries were added to Lucene 3.4 but I'm not sure whether they're available to users who are using Hibernate Search. It seems if one is wanting to do parent/child relational queries, perhaps my above approach isn't correct?
Unfortunately I haven't found much clear documentation on this and so any help and/or tips are greatly appreciative!
Domain Model:NOTE: Not all annotations, getter/setters are provided. This is meant to be just for illustration of the test-case.
Code:
@Entity
@Table(name="products"
@Indexed
public class Product
{
@Id
@GeneratedValue
private Long productId;
@Column(name="name",length=80,nullable=false)
@Field(index=Index.Yes, analyze=Analyze.YES, store=Store.NO)
private String name;
@OneToMany(mappedBy="product")
@IndexEmbedded
private List<Description> descriptions;
@OneToMany(mappedBy="product")
@IndexEmbedded
private List<SKU> skus;
}
@Entity
@Table(name="product_descriptions")
@Indexed
public class Description
{
@Id
@GeneratedValue
private Long id;
@Column(name="language_id",nullable=false)
@Field(index=Index.YES, analyze.Analyze.NO, store=Store.NO)
private Long languageId;
@Column(name="description",length=2000)
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
private String description;
@ManyToOne
@JoinColumn(name="product_id")
@ContainedIn
private Product product;
}
@Entity
@Table(name="product_skus")
@Indexed
public class SKU
{
@Id
@GeneratedValue
private Long id;
@Column(name="sku",length=80)
@Field(index=Index.YES, analyze=Analyze.NO, store=Store.NO)
private String sku;
@Column(name="sku_type")
@Field(index=Index.YES, analyze=Analyze.NO, store=Store.NO)
private Long type;
@ManyToOne
@JoinColumn(name="product_id")
@ContainedIn
private Product product;
}