Slow Hibernate Search Index

3

This is a crosspost I did in stackoverflow in English. It is difficult to understand (and correct) this problem. I'll post it here to see if anyone in our community has ever been through this and knows what might be going on.

What happens is that I have a view in Oracle . This view takes a while to execute (~ 7 seconds), although it returns few records. Return about 5756 lines when I make a simple query as select * from my_view;

So far I have no problem. The problem occurs in my project where I have a Hibernate entity mapped to that view and also an index mapping of Hibernate Search so I can do a fulltext search across the entire index.

Better to show the code. This is my mapped entity:

@Entity
@Indexed
@Table(name = "my_view")
public class Person implements Serializable {

    private static final long serialVersionUID = 244555315052436669L;

    @Id
    @Column(name = "id", insertable = false, updatable = false)
    private Long id;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "name", insertable = false, updatable = false)
    private String name;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "email", insertable = false, updatable = false)
    private String email;

    @Field(store = Store.NO, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "user", insertable = false, updatable = false)
    private String user;

    @Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "phone", insertable = false, updatable = false)
    private String phone;

    //Getters and Setters ommited
}

Note that there is normal mapping of Hibernate / JPA and Hibernate Search (% with%, for example). So far legal. I think it's all right. So I created a method to create the index. The method is this:

public void index() throws DAOException {
    FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(this.entityManager);

    try {
        fullTextEntityManager.createIndexer(Person.class)
            .purgeAllOnStart(Boolean.TRUE)
            .optimizeOnFinish(Boolean.TRUE)
            .startAndWait();
    }
    catch (InterruptedException e) {
        logger.error("Error creating index", e);
        throw new DAOException(e);
    }
}

Here too, all right. It creates the index in the correct file system. Now the problem comes. The search itself on the created index. This search, because it is a fulltext search, should be extremely fast, after all, Hibernate Search is built on top of Lucene, which values performance.

When I do a search for terms, until it goes well (not so well, but it goes), the problem occurs when I search without any terms, that is, when I want to return all records of the index. It takes more than 40 seconds a search without terms! An absurd time for an indexed search.

The code for my search without terms:

FullTextEntityManager fullTextEm = Search.getFullTextEntityManager(this.entityManager);
QueryBuilder qb = fullTextEm.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get();
FullTextQuery fullTextQuery = fullTextEm.createFullTextQuery(qb.all().createQuery());
Sort sortField = new Sort(new SortField("name", SortField.STRING));
fullTextQuery.setSort(sortField);
return fullTextQuery.getResultList();

I've been beating head for some time without success. Any suggestions or tips are welcome!

    
asked by anonymous 25.03.2014 / 02:27

1 answer

2

Problem solved.

What happens is that Hibernate Search retrieves the data in the index, uses that data to search the view database and retrieves the data the mapped entity. When fetching the data in view , the query execution time was time consuming and this slowed down my application.

To solve the problem I had to use the Projections of Hibernate Search. This feature allows me to store the entity information in the index, leaving the index larger, but much faster.

Going straight to the point, what I had to do was change my entity so that it saves the data in the index using the store = Store.YES annotation. My entity looks like this:

@Entity
@Indexed
@Table(name = "my_view")
public class Person implements Serializable {

    private static final long serialVersionUID = 244555315052436669L;

    @Id
    @Column(name = "id", insertable = false, updatable = false)
    private Long id;

    @Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "name", insertable = false, updatable = false)
    private String name;

    @Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "email", insertable = false, updatable = false)
    private String email;

    @Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "user", insertable = false, updatable = false)
    private String user;

    @Field(store = Store.YES, index = Index.YES, analyze = Analyze.YES)
    @Column(name = "phone", insertable = false, updatable = false)
    private String phone;

    //Getters and Setters ommited
}

Then, I had to change the way I did the query over the index. This change is to specify that I want to use projections . So my index search method looks like this:

FullTextEntityManager fullTextEm = Search.getFullTextEntityManager(this.entityManager);
QueryBuilder qb = fullTextEm.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get();
FullTextQuery fullTextQuery = fullTextEm.createFullTextQuery(qb.all().createQuery());

// Adicionei essa linha para usar projections
fullTextQuery.setProjection("id", "name", "email", "user", "phone");

Sort sortField = new Sort(new SortField("name", SortField.STRING));
fullTextQuery.setSort(sortField);
return fullTextQuery.getResultList();

Now the problem with using Projections is that Hibernate Search returns an array list of objects and not the list with my entity. In other words, Hibernate Search, with Projections, returns a List<Object[]> and without Projections returns List<Person> . So I had to create an auxiliary method to convert List<Object[]> to List<Person> . The code:

private List<Person> toList(List<Object[]> objPeople) {
    List<Person> lstPeople = new LinkedList<Person>();
    Person Person = null;

    for(Object[] objPerson : objPeople) {
        Person p = new Person();
        p.setId(Long.parseLong(objPerson[0].toString()));
        p.setName(String.valueOf(objPerson[1] == null ? "" : objPerson[1]));
        p.setEmail(String.valueOf(objPerson[2] == null ? "" : objPerson[2]));
        p.setUser(String.valueOf(objPerson[3] == null ? "" : objPerson[3]));
        p.setPhone(String.valueOf(objPerson[4] == null ? "" : objPerson[4]));
        lstPeople.add(p);
    }

    return lstPeople;
}

And soon ! Now it works and a lot, but very fast. The search on the index without keyword some delay milliseconds.

    
26.03.2014 / 20:46