001: /*
002: * $Header: /cvsroot/mvnforum/mvnforum/src/com/mvnforum/search/member/MemberSearchQuery.java,v 1.13 2007/10/12 08:12:15 lexuanttkhtn Exp $
003: * $Author: lexuanttkhtn $
004: * $Revision: 1.13 $
005: * $Date: 2007/10/12 08:12:15 $
006: *
007: * ====================================================================
008: *
009: * Copyright (C) 2002-2007 by MyVietnam.net
010: *
011: * All copyright notices regarding mvnForum MUST remain
012: * intact in the scripts and in the outputted HTML.
013: * The "powered by" text/logo with a link back to
014: * http://www.mvnForum.com and http://www.MyVietnam.net in
015: * the footer of the pages MUST remain visible when the pages
016: * are viewed on the internet or intranet.
017: *
018: * This program is free software; you can redistribute it and/or modify
019: * it under the terms of the GNU General Public License as published by
020: * the Free Software Foundation; either version 2 of the License, or
021: * any later version.
022: *
023: * This program is distributed in the hope that it will be useful,
024: * but WITHOUT ANY WARRANTY; without even the implied warranty of
025: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
026: * GNU General Public License for more details.
027: *
028: * You should have received a copy of the GNU General Public License
029: * along with this program; if not, write to the Free Software
030: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
031: *
032: * Support can be obtained from support forums at:
033: * http://www.mvnForum.com/mvnforum/index
034: *
035: * Correspondence and Marketing Questions can be sent to:
036: * info at MyVietnam net
037: *
038: * @author: Minh Nguyen
039: * @author: Dejan Krsmanovic dejan_krsmanovic@yahoo.com
040: */
041: package com.mvnforum.search.member;
042:
043: import java.io.IOException;
044: import java.sql.Timestamp;
045: import java.util.ArrayList;
046: import java.util.Collection;
047:
048: import net.myvietnam.mvncore.exception.DatabaseException;
049: import net.myvietnam.mvncore.exception.ObjectNotFoundException;
050:
051: import org.apache.commons.logging.Log;
052: import org.apache.commons.logging.LogFactory;
053: import org.apache.lucene.document.DateTools;
054: import org.apache.lucene.document.Document;
055: import org.apache.lucene.document.DateTools.Resolution;
056: import org.apache.lucene.index.Term;
057: import org.apache.lucene.queryParser.ParseException;
058: import org.apache.lucene.search.*;
059: import org.apache.lucene.store.Directory;
060:
061: import com.mvnforum.db.DAOFactory;
062: import com.mvnforum.db.MemberBean;
063: import com.mvnforum.service.MvnForumServiceFactory;
064: import com.mvnforum.service.SearchService;
065:
066: /**
067: * This class is used for specifying query that should be searched for. Query
068: * can contain keywords and further it can be filtered by specifying member
069: * name of the Member, address as well as date interval for searching.
070: *
071: * searchString contains one or more keywords. Each keyword can use wildcards.
072: * ? for single character and * for multiple characters.
073: * For specifying boolean operators AND and OR operators can be used.....
074: *
075: * For all available options consult Lucene documentation http://jakarta.apache.org/lucene
076: *
077: * @author Dejan Krsmanovic dejan_krsmanovic@yahoo.com
078: */
079: public class MemberSearchQuery {
080:
081: // search engine properties
082: private static Log log = LogFactory.getLog(MemberSearchQuery.class);
083:
084: // search object constants
085: public static final int SEARCH_ANY_DATE = 0;
086:
087: public static final int SEARCH_NEWER = 1;
088: public static final int SEARCH_OLDER = 2;
089:
090: // search object properties
091: private String memberEmailKey = null;
092: private String memberNameKey = null;
093:
094: private String memberLastNameKey = null;
095: private String memberFirstNameKey = null;
096: //private String memberGender = null;
097: private String memberCountry = null;
098:
099: private Timestamp from = null;
100: private Timestamp to = null;
101:
102: private int hitCount = 0;
103: private Collection searchResult = null;
104:
105: public MemberSearchQuery() {
106: }
107:
108: /**
109: * Set string that should be searched for.
110: * @param memberNameKey
111: */
112: public void setMemberNameKey(String memberNameKey) {
113: this .memberNameKey = memberNameKey;
114: }
115:
116: public void setMemberEmailKey(String memberEmailKey) {
117: this .memberEmailKey = memberEmailKey;
118: }
119:
120: public void setFromDate(Timestamp from) {
121: this .from = from;
122: }
123:
124: public void setToDate(Timestamp to) {
125: this .to = to;
126: }
127:
128: public void setMemberLastNameKey(String lastNameKey) {
129: this .memberLastNameKey = lastNameKey;
130: }
131:
132: public void setMemberFirstNameKey(String firstNameKey) {
133: this .memberFirstNameKey = firstNameKey;
134: }
135:
136: public void setCountry(String country) {
137: this .memberCountry = country;
138: }
139:
140: // Note that with IndexSearcher, the directory is closed automatically
141: protected IndexSearcher getSearcher(Directory directory)
142: throws IOException {
143: try {
144: IndexSearcher searcher = new IndexSearcher(directory);
145: return searcher;
146: } catch (IOException ex) {
147: // we throw new IOException because the original exception
148: // contain sensitive directory information
149: log
150: .error(
151: "Cannot access the lucene search index for query. Please check if you have configed mvnForumHome properly. You can also go to Admin Zone to rebuild the Lucene index files.",
152: ex);
153: //@todo : localize me
154: throw new IOException(
155: "Cannot access the lucene search index. Please report this error to web site Administrator (check mvnForumHome or rebuild Lucene index).");
156: }
157: }
158:
159: public void searchDocuments(int offset, int rowsToReturn)
160: throws IOException, DatabaseException,
161: ObjectNotFoundException {
162:
163: // check if those search key is empty??
164: //Build the query
165: BooleanQuery query = new BooleanQuery();//query.
166: try {
167: Query memberNameQuery = getMemberNameQuery();
168: if (memberNameQuery != null) {
169: query.add(memberNameQuery, BooleanClause.Occur.MUST);
170: log.debug("memberNameQuery = " + memberNameQuery);
171: }
172:
173: Query memberEmailQuery = getMemberEmailQuery();
174: if (memberEmailQuery != null) {
175: query.add(memberEmailQuery, BooleanClause.Occur.MUST);
176: log.debug("memberEmailQuery = " + memberEmailQuery);
177: }
178:
179: Query memberLastNameQuery = getMemberLastNameQuery();
180: if (memberLastNameQuery != null) {
181: query
182: .add(memberLastNameQuery,
183: BooleanClause.Occur.MUST);
184: log.debug("memberLastNameQuery = "
185: + memberLastNameQuery);
186: }
187:
188: Query memberFirstNameQuery = getMemberFirstNameQuery();
189: if (memberFirstNameQuery != null) {
190: query.add(memberFirstNameQuery,
191: BooleanClause.Occur.MUST);
192: log.debug("memberFirstNameQuery = "
193: + memberFirstNameQuery);
194: }
195:
196: Query memberCountryQuery = getMemberCountryQuery();
197: if (memberCountryQuery != null) {
198: query.add(memberCountryQuery, BooleanClause.Occur.MUST);
199: log.debug("memberCountryQuery = " + memberCountryQuery);
200: }
201: } catch (ParseException pe) {
202: log.error("Cannot parse the search query", pe);
203: }
204: log.debug("booleanQuery = " + query);
205:
206: RangeFilter dateFilter = null;
207: if (from != null && to != null) {
208: dateFilter = new RangeFilter(
209: MemberIndexer.FIELD_CREATION_DATE,
210: DateTools
211: .dateToString(from, Resolution.MILLISECOND),
212: DateTools.dateToString(to, Resolution.MILLISECOND),
213: true, true);
214: } else if (from != null) {
215: dateFilter = RangeFilter
216: .More(MemberIndexer.FIELD_CREATION_DATE, DateTools
217: .dateToString(from, Resolution.MILLISECOND));
218: } else if (to != null) {
219: dateFilter = RangeFilter.Less(
220: MemberIndexer.FIELD_CREATION_DATE, DateTools
221: .dateToString(to, Resolution.MILLISECOND));
222: }
223:
224: //Now search the documents
225: Directory directory = null;
226: IndexSearcher searcher = null;
227: try {
228: SearchService service = MvnForumServiceFactory
229: .getMvnForumService().getSearchService();
230: directory = service.getSearchMemberIndexDir();
231: searcher = getSearcher(directory);
232:
233: //If dateFilter set then use it
234: Hits memberHits = null;
235: //dateFilter = null;
236: if (dateFilter != null) {
237: memberHits = searcher.search(query, dateFilter);
238: } else {
239: memberHits = searcher.search(query);
240: }
241: hitCount = memberHits.length();
242: log.debug("[ HIT COUNT ]" + hitCount);
243: searchResult = getMembers(memberHits, offset, rowsToReturn);
244: } catch (IOException ex) {
245: throw ex;
246: } finally {
247: // NOTE that we don't close directory because searcher.close() already do that
248: if (searcher != null) {
249: try {
250: searcher.close();
251: } catch (IOException ex) {
252: log.debug("Error closing Lucene IndexSearcher", ex);
253: }
254: }
255: }
256: }
257:
258: public int getHitCount() {
259: return hitCount;
260: }
261:
262: public Collection getMemberResult() {
263: if (searchResult == null) {
264: //create an empty list, in case result is null
265: searchResult = new ArrayList();
266: }
267: return searchResult;
268: }
269:
270: private Collection getMembers(Hits MemberHits, int offset,
271: int rowsToReturn) throws IOException,
272: ObjectNotFoundException, DatabaseException {
273:
274: if (offset < 0)
275: throw new IllegalArgumentException(
276: "The offset < 0 is not allowed.");
277: if (rowsToReturn <= 0)
278: throw new IllegalArgumentException(
279: "The rowsToReturn <= 0 is not allowed.");
280:
281: //int hitCount = getHitCount();
282: ArrayList retValue = new ArrayList(hitCount);
283:
284: for (int i = offset; (i < offset + rowsToReturn)
285: && (i < hitCount); i++) {
286: Document memberDocument = MemberHits.doc(i);
287: int memberID = Integer.parseInt(memberDocument
288: .get(MemberIndexer.FIELD_MEMBER_ID));
289: MemberBean MemberBean = DAOFactory.getMemberDAO()
290: .getMember(memberID);
291: retValue.add(MemberBean);
292: }
293: return retValue;
294: }
295:
296: private Query getMemberNameQuery() throws ParseException {
297: if (memberNameKey == null || memberNameKey.equals("")) {
298: return null;
299: }
300: Term memberNameTerm = new Term(MemberIndexer.FIELD_MEMBER_NAME,
301: memberNameKey);
302: Query memberNameQuery = new TermQuery(memberNameTerm);
303: return memberNameQuery;
304: }
305:
306: private Query getMemberEmailQuery() throws ParseException {
307: if (memberEmailKey == null || memberEmailKey.equals("")) {
308: return null;
309: }
310: Term memberEmailTerm = new Term(
311: MemberIndexer.FIELD_MEMBER_EMAIL, memberEmailKey);
312: Query memberEmailQuery = new TermQuery(memberEmailTerm);
313: return memberEmailQuery;
314: }
315:
316: private Query getMemberQuery(String fieldName, String keyQuery)
317: throws ParseException {
318: if (keyQuery == null || keyQuery.equals("")) {
319: return null;
320: }
321: Term keyTerm = new Term(fieldName, keyQuery);
322: Query memberQuery = new TermQuery(keyTerm);
323: return memberQuery;
324: }
325:
326: private Query getMemberLastNameQuery() throws ParseException {
327: return getMemberQuery(MemberIndexer.FIELD_MEMBER_LASTNAME,
328: memberLastNameKey);
329: }
330:
331: private Query getMemberFirstNameQuery() throws ParseException {
332: return getMemberQuery(MemberIndexer.FIELD_MEMBER_FIRSTNAME,
333: memberFirstNameKey);
334: }
335:
336: private Query getMemberCountryQuery() throws ParseException {
337: return getMemberQuery(MemberIndexer.FIELD_MEMBER_COUNTRY,
338: memberCountry);
339: }
340:
341: }
|