Skip to content

Commit

Permalink
TRUNK-4366 Follow up changes
Browse files Browse the repository at this point in the history
  • Loading branch information
rkorytkowski committed Jun 20, 2014
1 parent ccbd1df commit 95e388f
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 53 deletions.
4 changes: 2 additions & 2 deletions api/src/main/java/org/openmrs/Concept.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import org.openmrs.api.ConceptNameType;
import org.openmrs.api.ConceptService;
import org.openmrs.api.context.Context;
import org.openmrs.api.db.hibernate.search.FilterFactory;
import org.openmrs.api.db.hibernate.search.TermsFilterFactory;
import org.openmrs.util.LocaleUtility;
import org.openmrs.util.OpenmrsUtil;
import org.simpleframework.xml.Attribute;
Expand Down Expand Up @@ -75,7 +75,7 @@
*/
@Root
@Indexed
@FullTextFilterDefs( { @FullTextFilterDef(name = "filterFactory", impl = FilterFactory.class) })
@FullTextFilterDefs( { @FullTextFilterDef(name = "termsFilterFactory", impl = TermsFilterFactory.class) })
public class Concept extends BaseOpenmrsObject implements Auditable, Retireable, java.io.Serializable, Attributable<Concept> {

public static final long serialVersionUID = 57332L;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -599,8 +599,8 @@ public List<Concept> getConcepts(final String name, final Locale loc, final bool
}

final List<ConceptName> names = LuceneQuery.newQuery(query.toString(), sessionFactory.getCurrentSession(),
ConceptName.class).filter("concept.datatype.conceptDatatypeId", transformToIds(datatypes)).filter(
"concept.conceptClass.conceptClassId", transformToIds(classes)).filter("concept.retired", "false").skipSame(
ConceptName.class).include("concept.datatype.conceptDatatypeId", transformToIds(datatypes)).include(
"concept.conceptClass.conceptClassId", transformToIds(classes)).include("concept.retired", "false").skipSame(
"concept.conceptId").list();

final List<Concept> concepts = Lists.transform(names, transformNameToConcept);
Expand Down Expand Up @@ -1346,10 +1346,10 @@ private LuceneQuery<ConceptName> createConceptNameQuery(final String phrase, Lis
}

LuceneQuery<ConceptName> luceneQuery = LuceneQuery.newQuery(query.toString(), sessionFactory.getCurrentSession(),
ConceptName.class).skipSame("concept.conceptId").filter("concept.conceptClass.conceptClassId",
transformToIds(requireClasses)).filter("-concept.conceptClass.conceptClassId", transformToIds(excludeClasses))
.filter("concept.datatype.conceptDatatypeId", transformToIds(requireDatatypes)).filter(
"-concept.datatype.conceptDatatypeId", transformToIds(excludeDatatypes));
ConceptName.class).include("concept.conceptClass.conceptClassId", transformToIds(requireClasses)).exclude(
"concept.conceptClass.conceptClassId", transformToIds(excludeClasses)).include(
"concept.datatype.conceptDatatypeId", transformToIds(requireDatatypes)).exclude(
"concept.datatype.conceptDatatypeId", transformToIds(excludeDatatypes));

if (answersToConcept != null) {
Collection<ConceptAnswer> answers = answersToConcept.getAnswers(false);
Expand All @@ -1359,14 +1359,16 @@ private LuceneQuery<ConceptName> createConceptNameQuery(final String phrase, Lis
for (ConceptAnswer conceptAnswer : answersToConcept.getAnswers(false)) {
ids.add(conceptAnswer.getAnswerConcept().getId());
}
luceneQuery.filter("concept.conceptId", ids.toArray(new Object[0]));
luceneQuery.include("concept.conceptId", ids.toArray(new Object[0]));
}
}

if (!includeRetired) {
luceneQuery.filter("concept.retired", "false");
luceneQuery.include("concept.retired", "false");
}

luceneQuery.skipSame("concept.conceptId");

return luceneQuery;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@
*/
package org.openmrs.api.db.hibernate.search;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.lucene.analysis.Analyzer;
Expand Down Expand Up @@ -43,7 +42,9 @@ public abstract class LuceneQuery<T> extends SearchQuery<T> {

private FullTextQuery fullTextQuery;

private Map<String, Object> fieldMap;
private Set<Set<Term>> includeTerms = new HashSet<Set<Term>>();

private Set<Term> excludeTerms = new HashSet<Term>();

public static <T> LuceneQuery<T> newQuery(final String query, final Session session, final Class<T> type) {
return new LuceneQuery<T>(
Expand All @@ -70,26 +71,47 @@ public LuceneQuery(Session session, Class<T> type) {
buildQuery();
}

private void addFilter(String field, Object value) {
if (fieldMap == null) {
fieldMap = new HashMap<String, Object>();
public LuceneQuery<T> include(String field, Object value) {
if (value != null) {
include(field, new Object[] { value });
}
fieldMap.put(field, value);
// update filters
fullTextQuery.enableFullTextFilter("filterFactory").setParameter("fieldMap", fieldMap);

return this;
}

public LuceneQuery<T> filter(String field, Object value) {
public LuceneQuery<T> include(String field, Object[] values) {
if (values != null && values.length != 0) {
Set<Term> terms = new HashSet<Term>();
for (Object value : values) {
terms.add(new Term(field, value.toString()));
}
includeTerms.add(terms);

fullTextQuery.enableFullTextFilter("termsFilterFactory").setParameter("includeTerms", includeTerms)
.setParameter("excludeTerms", excludeTerms);
}

return this;
}

public LuceneQuery<T> exclude(String field, Object value) {
if (value != null) {
addFilter(field, value);
exclude(field, new Object[] { value });
}

return this;
}

public LuceneQuery<T> filter(String field, Object[] values) {
public LuceneQuery<T> exclude(String field, Object[] values) {
if (values != null && values.length != 0) {
addFilter(field, values);
for (Object value : values) {
excludeTerms.add(new Term(field, value.toString()));
}

fullTextQuery.enableFullTextFilter("termsFilterFactory").setParameter("includeTerms", includeTerms)
.setParameter("excludeTerms", excludeTerms);
}

return this;
}

Expand Down Expand Up @@ -130,6 +152,10 @@ protected FullTextSession getFullTextSession() {
* Skip elements, values of which repeat in the given field.
* <p>
* Only the first element will be included in the results.
* <p>
* <b>Note:</b> For performance reasons you should call this method as last when constructing a
* query. When called it will project the query and create a filter to eliminate
* duplicates.
*
* @param field
* @return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,64 @@
*/
package org.openmrs.api.db.hibernate.search;

import java.util.HashSet;
import java.util.Set;

import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.CachingWrapperFilter;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.CachingWrapperFilter;
import org.apache.lucene.search.QueryWrapperFilter;
import org.apache.lucene.search.TermQuery;
import org.hibernate.search.annotations.Factory;
import org.hibernate.search.annotations.Key;
import org.hibernate.search.filter.StandardFilterKey;
import org.hibernate.search.filter.FilterKey;
import org.hibernate.search.filter.StandardFilterKey;

import java.util.List;
import java.util.Map;

public class FilterFactory {
public class TermsFilterFactory {

private Set<Set<Term>> includeTerms = new HashSet<Set<Term>>();

private Set<Term> excludeTerms = new HashSet<Term>();

private Map<String, Object> fieldMap;
public void setIncludeTerms(Set<Set<Term>> terms) {
this.includeTerms = new HashSet<Set<Term>>(terms);
}

public void setFieldMap(Map<String, Object> map) {
this.fieldMap = map;
public void setExcludeTerms(Set<Term> terms) {
this.excludeTerms = new HashSet<Term>(terms);
}

@Key
public FilterKey getKey() {
StandardFilterKey key = new StandardFilterKey();
key.addParameter(fieldMap);
key.addParameter(includeTerms);
key.addParameter(excludeTerms);
return key;
}

@Factory
public Filter getFilter() {
BooleanQuery query = new BooleanQuery();
for (Map.Entry<String, Object> entry : fieldMap.entrySet()) {
String field = entry.getKey();
Object value = entry.getValue();
if (value.getClass().isArray()) {
BooleanQuery arrayQuery = new BooleanQuery();
BooleanClause.Occur clause = (field.startsWith("-")) ? BooleanClause.Occur.MUST_NOT
: BooleanClause.Occur.SHOULD;
if (clause == BooleanClause.Occur.MUST_NOT) {
arrayQuery.add(new MatchAllDocsQuery(), BooleanClause.Occur.MUST);
field = field.substring(1);
}
Object[] values = (Object[]) value;
for (Object val : values) {
arrayQuery.add(new TermQuery(new Term(field, val.toString())), clause);
}
query.add(arrayQuery, BooleanClause.Occur.MUST);
} else {
query.add(new TermQuery(new Term(field, value.toString())), BooleanClause.Occur.MUST);

for (Set<Term> terms : includeTerms) {
BooleanQuery subquery = new BooleanQuery();
for (Term term : terms) {
subquery.add(new TermQuery(term), Occur.SHOULD);
}
query.add(subquery, Occur.MUST);
}

if (includeTerms.isEmpty()) {
query.add(new MatchAllDocsQuery(), Occur.MUST);
}

for (Term term : excludeTerms) {
query.add(new TermQuery(term), Occur.MUST_NOT);
}

return new CachingWrapperFilter(new QueryWrapperFilter(query));
}
}

0 comments on commit 95e388f

Please sign in to comment.