2015-01-29 4 views
1

최대 절전 모드 검색 필터로 부울 로직을 구현하는 데 문제가 있습니다. 그룹에 속할 수있는 사람이 있습니다. 모든 그룹에는 상태 카탈로그의 상태가 있습니다.컬렉션에서 Hibernate Search (Lucene) 필터

그룹 1이고 상태 2 인 모든 사용자를 필터링해야합니다. 두 개의 절에 대해 Occur.MUST와 함께 부울 쿼리를 사용하고 있지만 필터링 된 결과에는 목록이있는 사람이 포함됩니다 grops 그 중 하나가 1이고, 그룹의 상태 중 하나는, 예를 들면 2 :

person | group | status 
105  (1)  3 
105  2  3 
105  3  (2) 

188  (1)  3 
188  7  (2) 

197  (1)  4 
197  8  5 
197  9  (2) 

사용자 (105), (188) 및 (197)는 필터링 된 결과에 포함하지 않았다. 그것을 이루기위한 올바른 방법은 무엇입니까?

필터 :

BooleanQuery bq = new BooleanQuery(); 
TermQuery tqGroup = new TermQuery(new Term("groupPersons.id.groupId", "1")); 
TermQuery tqStatus = new TermQuery(new Term("groupPersons.status.id", "2")); 
bq.add(tqGroup, BooleanClause.Occur.MUST); 
bq.add(tqStatus, BooleanClause.Occur.MUST); 
filter = new QueryWrapperFilter(bq); 

사람 개체 :

... 
private List<GroupPerson> groupPersons = new ArrayList<GroupPerson>(0); 

@IndexedEmbedded 
@OneToMany(fetch = FetchType.LAZY, mappedBy = "person") 
public List<GroupPerson> getGroupPersons() { 
    return this.groupPersons; 
} 

GroupPerson 엔티티 :

... 

@EmbeddedId 
@AttributeOverrides({ 
     @AttributeOverride(name = "groupId", column = @Column(name = "group_id", nullable = false)), 
     @AttributeOverride(name = "personId", column = @Column(name = "person_id", nullable = false)) }) 
@NotNull 
@DocumentId 
@FieldBridge(impl = GroupPersonIdBridge.class) 
public GroupPersonId getId() { 
    return this.id; 
} 

... 

@ManyToOne(fetch = FetchType.LAZY) 
@JoinColumn(name = "status_id",nullable = false) 
@IndexedEmbedded 
@NotNull 
public Status getStatus() { 
    return this.Status; 
} 

OrganizationPersonIdBridge :

public Object get(String name, Document document) { 
    GroupPersonId id = new GroupPersonId(); 
    Field field = document.getField(name + ".groupId"); 
    id.setGroupId(Long.parseLong(field.stringValue())); 
    field = document.getField(name + ".personId"); 
    id.setPersonId(Long.parseLong(field.stringValue())); 
    return id; 
    } 

    public String objectToString(Object object) { 
    GroupPersonId id = (GroupPersonId) object; 
    StringBuilder sb = new StringBuilder(); 
    sb.append(id.getGroupId()) 
    .append(" ") 
    .append(id.getPersonId()); 
    return sb.toString(); 
    } 


    public void set(String name,Object value,Document document,LuceneOptions luceneOptions) { 
    GroupPersonId id = (GroupPersonId)value; 
    Store store = luceneOptions.getStore(); 
    Index index = luceneOptions.getIndex(); 
    TermVector termVector = luceneOptions.getTermVector(); 
    Float boost = luceneOptions.getBoost(); 
    //store each property in a unique field 
    Field field = new Field(name + ".groupId", id.getGroupId() + "", store, index, termVector); 
    field.setBoost(boost); 
    document.add(field); 

    field = new Field(name + ".personId", id.getPersonId() + "", store, index, termVector); 
    field.setBoost(boost); 
    document.add(field); 
    //store the unique string representation in the named field 
    field = new Field(name, 
    objectToString(id), 
    store, index, termVector); 
    field.setBoost(boost); 
    document.add(field); 
    } 

최대 절전 모드 검색 버전은 4.5.1입니다. 최종

답변

2

문제는 Lucene Document에는 연결이 없습니다. @IndexedEmbedded을 사용하면 모든 연관을 하나의 Lucene Document (사실 Lucene 색인에 추가되고 검색시 검색되는 항목)으로 효과적으로 병합합니다. Document에는 같은 이름의 필드가 여러 번 추가 될 수 있습니다. 귀하의 예를 고려하여 ID (105)와 Person에 대한 Document 필드 값 쌍에 다음 필드 이름이 포함됩니다 : 당신은 지금 당신의 쿼리를 보면

+-------------------------+-------------+ 
|  field name  | field value | 
+-------------------------+-------------+ 
| groupPersons.id.groupId |   1 | 
| groupPersons.id.groupId |   2 | 
| groupPersons.id.groupId |   3 | 
| groupPersons.status.id |   3 | 
| groupPersons.status.id |   3 | 
| groupPersons.status.id |   2 | 
+-------------------------+-------------+ 

, 당신은 사람 (105)가 일치하는 이유를 이해합니다. 두 부울 쿼리가 일치합니다.

어떻게 문제를 해결할 수 있습니까? 검색 할만한 고유 한 것을 확보해야합니다. 이 작업을 수행하는 한 가지 방법은 사용자 지정 브리지를 사용하여 그룹 및 상태를 단일 필드로 인덱싱하는 것입니다. 그런 다음 해당 필드를 대상으로하는 쿼리를 작성할 수 있습니다.

public class CustomClassBridge implements FieldBridge, Serializable { 
public final static String SEPARATOR = "-"; 

@Override 
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) { 
    GroupPerson gp = (GroupPerson)value; 
    String fieldValue = gp.getId().getGroupId() + SEPARATOR + gp.getStatus().getId(); 
    Field field = new Field(name, fieldValue, luceneOptions.getStore(), luceneOptions.getIndex(), luceneOptions.getTermVector()); 
    field.setBoost(luceneOptions.getBoost()); 
    document.add(field); 
} 
} 

는 클래스 수준에 GroupPerson 엔티티에 주석을 추가합니다 :

@ClassBridge(name="groupStatus",index=Index.YES, analyze=Analyze.NO, store=Store.YES, impl = CustomClassBridge.class) 

그리고 마지막으로 필터 : 같은 거랑 사람

+0

왜 그런 특정 행동이 필요한지 더 자세히 읽은 후 하디처럼 같은 결론에 도달했습니다. 필자는 다른 솔루션을 사용하여 목록을 매개 변수로 필터에 전달했습니다. 그러나 나는 당신이 제안하고있는 해결책을 더 좋아합니다. 감사! – Tvori

0

는 classBridge를 사용하여 솔루션을 여기에 케이스를 사용합니다

TermQuery tq = new TermQuery(new Term("groupPersons.groupStatus", 1 + CustomClassBridge.SEPARATOR + 2)); 
관련 문제