代码之家  ›  专栏  ›  技术社区  ›  TM00

嵌入式实体上的hibernate过滤器

  •  0
  • TM00  · 技术社区  · 6 年前

    我有一个dropwizard应用程序,它使用hibernate搜索。简而言之,我的数据库里有动物和它们的数据,我试图添加一个过滤器来获取特定品种列表中的动物。不幸的是,我的过滤器似乎不起作用,我不知道为什么。我怀疑这可能是我如何定义实体之间的关系,以及我如何在 FilterFactory ,但在我看来是对的。我已经实现了基于 Hibernate documentation . 相关类别如下:

    我的 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 回复  |  直到 6 年前
        1
  •  1
  •   TM00    6 年前

    结果,我的方法是正确的,我只是误解了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。