Фильтр гибернации на встроенных объектах - PullRequest
0 голосов
/ 02 июня 2018

У меня есть приложение Dropwizard, которое использует поиск в спящем режиме.Короче говоря, у меня есть животные и их данные в моей базе данных, и я пытаюсь добавить фильтр для получения животных определенного списка пород.К сожалению, кажется, что мой фильтр не работает, и я не могу понять, почему.Я подозреваю, что это может быть то, как я определил отношение между моими сущностями и как я пытаюсь ссылаться на атрибут породы в FilterFactory, но мне это кажется правильным.Я реализовал свой фильтр на основе документации Hibernate .Соответствующие классы:

Мой Animal класс:

@Entity
@Indexed
@FullTextFilterDef(name = "animalFilter", impl = AnimalFilterFactory.class)
@Table(name = "animal")
@JsonIgnoreProperties(ignoreUnknown = true)
public class Animal implements Serializable{

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @IndexedEmbedded
    @OneToOne(fetch = FetchType.LAZY,
            cascade =  CascadeType.ALL,
            mappedBy = "animal")
    private AnimalInfo info;
// rest of the class goes here
}

Мой AnimalInfo класс:

@Entity
@Table(name = "animal_info")
@JsonIgnoreProperties(ignoreUnknown = true)
public class AnimalInfo implements Serializable{

    @Id
    @Column(name = "animal_id")
    private Long animalId;

    @IndexedEmbedded
    @ManyToOne( cascade = CascadeType.ALL )
    @JoinColumn(name="breed_id")
    private AnimalBreed breed;
// rest of the class goes here
}

Мой AnimalBreed класс:

@Entity
@Table(name = "animal_breeds")
@JsonIgnoreProperties(ignoreUnknown = true)
public class AnimalBreed implements Serializable{

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /**
     * name of the breed which I want to filter my animals on.
     */
    @Field
    @Column(name = "name")
    private String name;

И мой класс фильтра: Может быть, оператор "info.breed.name" неверен?

public class AnimalFilterFactory {
    // list of breed names
    private List<String> breeds;

    public void setBreeds(List<String> breeds) {
        this.breeds = breeds;
    }    
    @Factory
    public Query getFilter() {

        BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
         // apply filter for all the breeds
        for (String breed : breeds) {
            booleanQuery.add(new TermQuery( new Term( "info.breed.name", breed ) ), Occur.SHOULD);
        }
        return booleanQuery.build();
    }

}

А в моем классе DAO, где я хочу применить фильтр:

public List<Animal> getForBreeds(List<String> breedNames){
        EntityManager em = this.currentSession();

        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);

        QueryBuilder qb = fullTextEntityManager.getSearchFactory()
                .buildQueryBuilder()
                .forEntity(Animal.class)
                .get();

        qb.sort().byNative(SortField.FIELD_SCORE).andByNative(new SortField("id", Type.STRING, true));


        org.apache.lucene.search.Query luceneQuery = qb.all().createQuery(); // get all the items 

        // apply filter
        FullTextQuery ftq = fullTextEntityManager.createFullTextQuery(luceneQuery, Animal.class);
        ftq.enableFullTextFilter("animalFilter").setParameter("breeds", breedNames);


        return ftq.getResultList();
}

Я проверил, что без применения фильтра возвращаются все сущности Животных в моей БД.Таким образом, кажется, что фильтр определенно является проблемой.

Любая помощь приветствуется.

1 Ответ

0 голосов
/ 03 июня 2018

Оказывается, мой подход был верным, я просто неправильно понял, как Lucene индексирует свои термины.например, порода "бостон терьер" индексируется как "бостон" и "терьер".Для фильтрации всей фразы необходимо использовать PhraseQuery вместо TermQuery.Я обновил свой фильтр следующим образом:

@Factory
    public Query getFilter() {

        BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();

        String fieldId = "info.breed.name";

        //booleanQuery.setMinimumNumberShouldMatch(1);
        for (String breed : breeds) {

            if(breed.contains(" ")) { // if multiple terms in breed
                PhraseQuery.Builder builder = new PhraseQuery.Builder();

                String[] terms = breed.split(" ");

                for (int i = 0; i < terms.length; i++) {
                    builder.add(new Term( fieldId, terms[i].toLowerCase() ), i);
                }

                PhraseQuery pq = builder.build();

                BooleanClause clause = new BooleanClause(pq, Occur.SHOULD);
                booleanQuery.add(clause);
            }else {
                // single term
                BooleanClause clause = new BooleanClause(new TermQuery( new Term(fieldId, breed.toLowerCase() ) ), Occur.SHOULD);
                booleanQuery.add(clause);
            }


        }

        BooleanQuery query = booleanQuery.build();
        return query;
    }

Для записи я понял это с помощью Luke , чтобы проверить поля индексированных сущностей и соответствующим образом скорректировать мой код.Просто убедитесь, что вы используете правильную версию Luke для своих индексов Lucene, так как существуют несовместимости версий.Версии Luke и Lucene работают параллельно друг другу.В моем случае я использовал версию 5.5.

...