Hibernate搜索元组查询

时间:2014-11-27 10:02:21

标签: hibernate-search

我有一个实体Message,它与实体Header有一对多的关系。如何创建基于元组的搜索查询,如

(message.headerKey="foo" and message.headerValue="123") and 
(message.headerKey="bar" and message.headerValue="456") 

当我在搜索条件中交换标题值时,我当前的逻辑也会匹配

(message.headerKey="foo" and message.headerValue="456") and 
(message.headerKey="bar" and message.headerValue="123") 

如何使用Hibernate Search API进行基于元组的查询?

这是我的消息实体:

@Entity
@Table(name="MESSAGE")

@Indexed
public class MessageEntity implements Serializable {

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

    @Column(name="message_timestamp")
    private Date timestamp;

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

    @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, mappedBy = "message")
    @IndexedEmbedded
    private List<HeaderEntity> headers;

    // Getters and Setters
}

这是我的标题实体:

@Entity
@Table(name="HEADER")
public class HeaderEntity implements Serializable {

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

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

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

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="message_id")
    private MessageEntity message;

    // Getters and Setters
}

这是我的搜索逻辑:

public List<MessageEntity> search(Header[] headers) {

        FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search.getFullTextEntityManager(mgr);
        QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(MessageEntity.class).get();
        TermMatchingContext onFieldKey = qb.keyword().onField("headers.headerKey");
        TermMatchingContext onFieldValue = qb.keyword().onField("headers.headerValue");

        BooleanJunction<BooleanJunction> bool = qb.bool();
        org.apache.lucene.search.Query query = null;
        for (Header header : headers) {
           bool.must(onFieldKey.matching(header.getKey()).createQuery());
           bool.must(onFieldValue.matching(header.getValue()).createQuery());
        }

        query = bool.createQuery();

        FullTextQuery persistenceQuery = fullTextEntityManager.createFullTextQuery(query, MessageEntity.class);

        persistenceQuery.setMaxResults(10);
        return persistenceQuery.getResultList();
    }

1 个答案:

答案 0 :(得分:0)

你的方法确实不行。问题是Lucene是一个平面数据结构,特别是关联(嵌入实体)只是“添加”到拥有实体的Lucene Document。在您的情况下,MessageEntity文档将分别包含headerKeyheaderValue个字段{{1}}。一次使用“foo”和“bar”作为值,将56“作为值。一次使用”123“和”456“作为值。没有任何概念认为其中两个值实际上是一对。

一种可能的解决方案是创建一个唯一的字段/值对。使用自定义类桥,您可以创建一个“keyValueField”,其中包含标题键和值作为连接值。在查询中,您将使用连接的查询参数来定位此字段。