3 * Copyright (C) 2012 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.api
.service
.search
;
12 import java
.util
.HashSet
;
13 import java
.util
.List
;
16 import org
.apache
.log4j
.Logger
;
17 import org
.apache
.lucene
.index
.Term
;
18 import org
.apache
.lucene
.queryParser
.ParseException
;
19 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
20 import org
.apache
.lucene
.search
.BooleanQuery
;
21 import org
.apache
.lucene
.search
.Query
;
22 import org
.apache
.lucene
.search
.TermQuery
;
23 import org
.apache
.lucene
.search
.WildcardQuery
;
25 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
26 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
27 import eu
.etaxonomy
.cdm
.hibernate
.search
.NotNullAwareIdBridge
;
28 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
29 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
30 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
33 * @author a.kohlbecker
37 public class QueryFactory
{
39 public static final Logger logger
= Logger
.getLogger(QueryFactory
.class);
41 private final LuceneSearch luceneSearch
;
43 Set
<String
> textFieldNames
= new HashSet
<String
>();
45 private BooleanQuery finalQuery
;
47 public Set
<String
> getTextFieldNames() {
48 return textFieldNames
;
51 public String
[] getTextFieldNamesAsArray() {
52 return textFieldNames
.toArray(new String
[textFieldNames
.size()]);
56 public QueryFactory(LuceneSearch luceneSearch
){
57 this.luceneSearch
= luceneSearch
;
61 * Creates a new Term query. Depending on whether <code>isTextField</code> is set true or not the
62 * supplied <code>queryString</code> will be parsed by using the according analyzer or not.
63 * Setting <code>isTextField</code> to <code>false</code> is useful for searching for uuids etc.
67 * @param isTextField whether this field is a field containing free text in contrast to e.g. ID fields.
68 * If <code>isTextField</code> to <code>true</code> the <code>queryString</code> will be parsed by
69 * using the according analyzer.
70 * @return the resulting <code>TermQuery</code> or <code>null</code> in case of an <code>ParseException</code>
72 * TODO consider throwing the ParseException !!!!
74 public Query
newTermQuery(String fieldName
, String queryString
, boolean isTextField
) {
76 String luceneQueryString
= fieldName
+ ":(" + queryString
+ ")";
78 textFieldNames
.add(fieldName
);
79 // in order to support the full query syntax we must use the parser
82 return luceneSearch
.parse(luceneQueryString
);
83 } catch (ParseException e
) {
88 return new TermQuery(new Term(fieldName
, queryString
));
93 * only to be used for text fields, see {@link #newTermQuery(String, String, boolean)}
96 * @return a {@link TermQuery} or a {@link WildcardQuery}
98 public Query
newTermQuery(String fieldName
, String queryString
){
99 return newTermQuery(fieldName
, queryString
, true);
103 * DefinedTerms are stored in the Lucene index by the
104 * {@link DefinedTermBaseClassBridge} in a consistent way. One field per
105 * language and also in one additional field for all languages. This method
106 * is a convenient means to retrieve a Lucene query string for such the
110 * name of the term field as in the Lucene index. The field must
111 * have been written to Lucene document by
112 * {@link DefinedTermBaseClassBridge}
115 * the languages to search for exclusively. Can be
116 * <code>null</code> to search in all languages
119 public Query
newDefinedTermQuery(String name
, String queryString
, List
<Language
> languages
) {
121 BooleanQuery localizedTermQuery
= new BooleanQuery();
122 localizedTermQuery
.add(newTermQuery(name
+ ".label", queryString
), Occur
.SHOULD
);
123 if(languages
== null || languages
.size() == 0){
124 localizedTermQuery
.add(newTermQuery(name
+ ".representation.text.ALL", queryString
), Occur
.SHOULD
);
125 localizedTermQuery
.add(newTermQuery(name
+ ".representation.label.ALL", queryString
), Occur
.SHOULD
);
126 localizedTermQuery
.add(newTermQuery(name
+ ".representation.abbreviatedLabel.ALL", queryString
), Occur
.SHOULD
);
129 for(Language lang
: languages
){
130 localizedTermQuery
.add(newTermQuery(name
+ ".representation.text." + lang
.getUuid().toString(), queryString
), Occur
.SHOULD
);
131 localizedTermQuery
.add(newTermQuery(name
+ ".representation.label." + lang
.getUuid().toString(), queryString
), Occur
.SHOULD
);
132 localizedTermQuery
.add(newTermQuery(name
+ ".representation.abbreviatedLabel." + lang
.getUuid().toString(), queryString
), Occur
.SHOULD
);
135 return localizedTermQuery
;
139 * MultilanguageString maps are stored in the Lucene index by the
140 * {@link MultilanguageTextFieldBridge } in a consistent way. One field per
141 * language and also in one additional field for all languages. This method
142 * is a convenient means to retrieve a Lucene query string for such the
146 * name of the term field as in the Lucene index. The field must
147 * have been written to Lucene document by
148 * {@link DefinedTermBaseClassBridge}
150 * the languages to search for exclusively. Can be
151 * <code>null</code> to search in all languages
154 public Query
newMultilanguageTextQuery(String name
, String queryString
, List
<Language
> languages
) {
156 BooleanQuery localizedTermQuery
= new BooleanQuery();
157 localizedTermQuery
.add(newTermQuery(name
+ ".label", queryString
), Occur
.SHOULD
);
158 if(languages
== null || languages
.size() == 0){
159 localizedTermQuery
.add(newTermQuery(name
+ ".ALL", queryString
), Occur
.SHOULD
);
161 for(Language lang
: languages
){
162 localizedTermQuery
.add(newTermQuery(name
+ "." + lang
.getUuid().toString(), queryString
), Occur
.SHOULD
);
165 return localizedTermQuery
;
174 public Query
newEntityIdQuery(String idFieldName
, CdmBase entitiy
){
175 return newTermQuery("inDescription.taxon.taxonNodes.classification.id", String
.valueOf(entitiy
.getId()), false);
182 public Query
newIsNotNullQuery(String idFieldName
){
183 return new TermQuery(new Term(NotNullAwareIdBridge
.notNullField(idFieldName
), NotNullAwareIdBridge
.NOT_NULL_VALUE
));
187 * creates a query for searching for documents in which the field specified by <code>uuidFieldName</code> matches at least one of the uuid
188 * of the <code>entities</code>, the sql equivalent of this is <code>WHERE uuidFieldName IN (uuid_1, uuid_2, ...) </code>.
189 * @param uuidFieldName
193 public Query
newEntityUuidQuery(String uuidFieldName
, List
<?
extends IdentifiableEntity
> entities
){
195 BooleanQuery uuidInQuery
= new BooleanQuery();
196 if(entities
!= null && entities
.size() > 0 ){
197 for(IdentifiableEntity entity
: entities
){
198 uuidInQuery
.add(newTermQuery(uuidFieldName
, entity
.getUuid().toString(), false), Occur
.SHOULD
);
204 public void setFinalQuery(BooleanQuery finalQuery
) {
205 this.finalQuery
= finalQuery
;
208 public BooleanQuery
getFinalQuery(){
212 public LuceneSearch
getLuceneSearch() {