0

I have three classes defined as:

1)Category class:-

@Entity
@Table(name = "CATEGORY")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Indexed
public class Category {

@Id
@GeneratedValue
private Long id;

@Field(index = Index.YES, store = Store.YES, analyzer = @Analyzer(definition = "ngram"))
private String categoryName;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "categoryId", referencedColumnName = "id")
@LazyCollection(LazyCollectionOption.TRUE)
@IndexedEmbedded
private List<SubCategory> subCategories;

private Long creationTime;

private Long updationTime;
}

2) SubCategory class:-

 @Entity
 @Table(name = "SUB_CATEGORY")
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
 @Indexed
 public class SubCategory {


@Id
@GeneratedValue
private Long id;

@Field(index = Index.YES,store = Store.YES,analyzer = @Analyzer(definition = "ngram1"))
private String subCategoryName;

@Field(index = Index.YES,store = Store.YES)
private Long categoryId;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "subCategoryId", referencedColumnName = "id")
@LazyCollection(LazyCollectionOption.TRUE)
@IndexedEmbedded
private List<Pages> pages;

private Long creationTime;
}

3) Pages class:-

 @Entity
 @Table(name = "PAGES")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Indexed
public class Pages {

@Id
@GeneratedValue
private Long id;

@Field(index = Index.YES,store = Store.YES,analyzer = @Analyzer(definition = "ngram2"))
private String pageName;

@Field(index = Index.YES,store = Store.YES,analyzer = @Analyzer(definition = "ngram2"))
private String pageDescription;

@Field(index = Index.YES,store = Store.YES,analyzer = @Analyzer(definition = "ngram2"))
private Long subCategoryId;

private Long creationTime;
}

Now the data is defined like:-

   Category              SubCategory              Pages
   --------              ------------             -------
   Vehicle                Car                     BMW
   Electricals            MotorCycle              Hero
   ...........            ........                Audi
   ...........            ........                ...... 
   Lapzz                  Laptop                  ......
                                                  Dell

Now I am stuck at getting the query that will search in all three classes using hibernate search(i.e.-If I search Lap*) I should get result from Categories,Subcategories and Pages and only the rows matching the query only not the complete object of Category.

eg-I should get in the result set the row containing Lapzz in categories and row containing Laptop in subcategories when I search for Lap*. Please help my find this solution.

Ayush Srivastava
  • 444
  • 1
  • 4
  • 13
  • What do you mean when you say "row"? In your results, do you want a mix of `Category`, `SubCategory` and `Pages` objects, depending on what matched? Or do you want exclusively `Page` objects, even when your crtieria matched a category (in which case you'd get all the pages of the matching category)? – yrodiere Jul 02 '18 at 15:05
  • I want mix of Category, Subcategy and Pages.Suppose I search for a query then the result should contain mixture of all three table data. – Ayush Srivastava Jul 03 '18 at 15:56

1 Answers1

0

This should do what you want, as far as I understand:

String searchTerms = ...;

QueryBuilder categoryQb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity( Category.class ).get();
QueryBuilder subCategoryQb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity( SubCategory.class ).get();
QueryBuilder pagesQb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity( Pages.class ).get();

Query categoryQuery = categoryQb.keyword()
    .onField( "categoryName" )
    .matching( searchTerms )
    .createQuery();
Query subCategoryQuery = subCategoryQb.keyword()
    .onField( "subCategoryName" )
    .matching( searchTerms )
    .createQuery();
Query pagesQuery = pagesQb.keyword()
    .onFields(
        "pageName",
        "pageDescription"
    )
    .matching( searchTerms )
    .createQuery();

Query luceneQuery = categoryQb.bool()
        .should( categoryQuery )
        .should( subCategoryQuery )
        .should( pagesQuery )
        .createQuery();

FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(
    luceneQuery,
    Category.class, SubCategory.class, Pages.class
);

List<?> results = fullTextQuery.getResultList();

Several warnings are necessary here:

  • since you are using ngram filters, you may need to use a different analyzer when querying; see this answer
  • your @Field annotation on Pages.subcategoryId is highly suspicious: it doesn't make sense to analyze a numeric value. For that matter, it's suspicious to store the ID of another entity in Pages, you'd generally want to have a field whose type is SubCategory instead and annotate it with @ManyToOne.
  • if you want your query to match a category that doesn't have the search terms in its description, but contains a page whose name or description contains the search terms, you will have to add an IndexedEmbedded and add the embedded fields ("pages.pageName", "pages.pageDescription", ...) to your search queries.
yrodiere
  • 9,280
  • 1
  • 13
  • 35