Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents a structured query, and can be
4
 *             constructed from an XML serialization conforming to
5
 *             pathquery.dtd. The printSQL() method can be used to print
6
 *             a SQL serialization of the query.
7
 *  Copyright: 2000 Regents of the University of California and the
8
 *             National Center for Ecological Analysis and Synthesis
9
 *    Authors: Matt Jones
10
 *
11
 *   '$Author: tao $'
12
 *     '$Date: 2007-04-17 15:58:29 -0700 (Tue, 17 Apr 2007) $'
13
 * '$Revision: 3242 $'
14
 *
15
 * This program is free software; you can redistribute it and/or modify
16
 * it under the terms of the GNU General Public License as published by
17
 * the Free Software Foundation; either version 2 of the License, or
18
 * (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU General Public License
26
 * along with this program; if not, write to the Free Software
27
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28
 */
29

    
30
package edu.ucsb.nceas.metacat;
31

    
32
import edu.ucsb.nceas.dbadapter.*;
33

    
34
import java.io.*;
35
import java.util.Hashtable;
36
import java.util.Stack;
37
import java.util.Vector;
38
import java.util.Enumeration;
39

    
40
import org.apache.log4j.Logger;
41

    
42
 /** a utility class that represents a group of terms in a query */
43
public  class QueryGroup {
44
    private String operator = null;  // indicates how query terms are combined
45
    private Vector children = null;  // the list of query terms and groups
46
    private int countPercentageSearchItem = 0;
47
    private Vector queryTermsWithSameValue = null;//this two dimension vectors.
48
                                                  //will hold query terms which has same search value.
49
    private Vector queryTerms = null;//this vector only holds query terms without same search value.
50
    private Vector queryGroupsChildren = null;
51
    private static Logger logMetacat = Logger.getLogger(QueryGroup.class);
52
    private static String UNION = "UNION";
53

    
54
    /**
55
     * construct a new QueryGroup
56
     *
57
     * @param operator the boolean conector used to connect query terms
58
     *                    in this query group
59
     */
60
    public QueryGroup(String operator) {
61
      this.operator = operator;
62
      children = new Vector();
63
      queryTermsWithSameValue = new Vector();
64
      queryTerms = new Vector();
65
      queryGroupsChildren = new Vector();
66
    }
67

    
68
    /**
69
     * Add a child QueryGroup to this QueryGroup
70
     *
71
     * @param qgroup the query group to be added to the list of terms
72
     */
73
    public void addChild(QueryGroup qgroup) {
74
      children.add((Object)qgroup);
75
      queryGroupsChildren.add(qgroup);
76
    }
77

    
78
    /**
79
     * Add a child QueryTerm to this QueryGroup
80
     *
81
     * @param qterm the query term to be added to the list of terms
82
     */
83
    public void addChild(QueryTerm qterm) {
84
      children.add((Object)qterm);
85
      handleNewQueryTerms(qterm);
86
      
87
    }
88

    
89
    /*
90
     * Retrieve an Enumeration of query terms for this QueryGroup
91
     */
92
    private Enumeration getChildren() {
93
      return children.elements();
94
    }
95

    
96
    public int getPercentageSymbolCount()
97
    {
98
      return countPercentageSearchItem;
99
    }
100

    
101
    /**
102
     * create a SQL serialization of the query that this instance represents
103
     */
104
    public String printSQL(boolean useXMLIndex) {
105
      StringBuffer self = new StringBuffer();
106
      StringBuffer queryString = new StringBuffer();
107

    
108
      boolean first = true;
109
      
110
      if (!queryTermsWithSameValue.isEmpty())
111
      {
112
    	  String sameValueQueryString = printSQLStringWithSameSearchValue();
113
    	  queryString.append(sameValueQueryString);
114
      }
115
      
116
      for (int i=0; i<queryGroupsChildren.size(); i++)
117
      {
118
      
119
        
120
            QueryGroup qg = (QueryGroup)queryGroupsChildren.elementAt(i);
121
        	String queryGroupSQL = qg.printSQL(useXMLIndex);
122
        	logMetacat.info("In QueryGroup.printSQL.. found a QueryGroup: " 
123
        			+ queryGroupSQL);       	
124
        	if (first) {
125
        		first = false;
126
        	} else {
127
        		if(!queryString.toString().equals("") && queryGroupSQL != null &&!queryGroupSQL.equals("")){
128
                    queryString.append(" " + operator + " ");
129
        		}
130
        	}
131
   		  	queryString.append(queryGroupSQL);
132
   		  	
133
   		  	// count percerntage number
134
   		  	int count = qg.getPercentageSymbolCount();
135
   		  	countPercentageSearchItem = countPercentageSearchItem + count;
136
      }
137
      
138
      for (int i=0; i<queryTerms.size(); i++)
139
      {
140
           QueryTerm qt = (QueryTerm)queryTerms.elementAt(i);
141
           String termQueryString = qt.printSQL(useXMLIndex);
142
       	   logMetacat.info("In QueryGroup.printSQL.. found a QueryGroup: " 
143
        			+ termQueryString);
144
           if(!(qt.getSearchMode().equals("contains") && qt.getValue().equals("%"))){
145
        	   if (first) {
146
                   first = false;
147
               } else {
148
                   if(!queryString.toString().equals("")){
149
                       queryString.append(" " + operator + " ");
150
                   }
151
               }
152
               queryString.append(termQueryString);
153
           
154
           // count percerntage number
155
           int count = qt.getPercentageSymbolCount();
156
           countPercentageSearchItem = countPercentageSearchItem + count;
157
        } 
158
      }
159

    
160
      if(!queryString.toString().equals("")){
161
          self.append("(");
162
          self.append(queryString.toString());
163
          self.append(")");
164
      }
165
      
166
      logMetacat.info("In QueryGroup.printSQL.. final query returned is: " 
167
			+ self.toString());
168
      return self.toString();
169
    }
170
    
171
    
172
    
173
    
174
    /*
175
     * If every query term in a queryGroup share a search value, we should
176
     * use a new query to replace the original query term query in order to
177
     * improve performance
178
     */
179
    private String printSQLStringWithSameSearchValue()
180
    {
181
    	String sql ="";
182
    	String value ="";
183
    	StringBuffer sqlBuff = new StringBuffer();
184
    	Vector pathVector = new Vector();
185
    	int index =0;
186
    	if (queryTermsWithSameValue != null)
187
    	{
188
    		boolean firstVector = true;
189
    		for (int j=0; j<queryTermsWithSameValue.size(); j++)
190
    		{
191
    	   		Vector queryTermVector = (Vector)queryTermsWithSameValue.elementAt(j);
192
	    		QueryTerm term1 = (QueryTerm)queryTermVector.elementAt(0);
193
	        	value = term1.getValue();
194
	        	boolean first = true;
195
	        	if (firstVector)
196
	        	{
197
				  firstVector = false;
198
	        	}
199
	        	else
200
	        	{
201
	        		sqlBuff.append(" "+operator+" ");
202
	        	}
203
	        	sqlBuff.append("SELECT DISTINCT docid FROM xml_path_index WHERE UPPER(nodedata) LIKE '%");
204
	        	if (value != null)
205
	        	{
206
	        	    sqlBuff.append(value.toUpperCase());
207
	        	}
208
	        	else
209
	        	{
210
	        		sqlBuff.append(value);
211
	        	}
212
				sqlBuff.append("%' AND path IN (");
213
	    		//gets every path in query term object
214
	    		for (int i=0; i<queryTermVector.size(); i++)
215
	    		{
216
	    			QueryTerm term = (QueryTerm)queryTermVector.elementAt(i);
217
	    			value = term.getValue();
218
	    			String path = term.getPathExpression();
219
	    			if (path != null && !path.equals(""))
220
	    			{
221
	    				if (first)
222
	    				{
223
	    					first = false;
224
	    					sqlBuff.append("'");
225
	    					sqlBuff.append(path);
226
	    					sqlBuff.append("'");
227
	    					
228
	    				}
229
	    				else
230
	    				{
231
	    					sqlBuff.append(",'");
232
	    					sqlBuff.append(path);
233
	    					sqlBuff.append("'");
234
	    				}
235
	    				index++;
236
	     				if (value != null && (value.equals("%") || value.equals("%%%")))
237
	                    {
238
	    				  countPercentageSearchItem++;
239
	                    }
240
    			     }
241
    		    }
242
    		    sqlBuff.append(")");
243
    	
244
    	    }
245
    	}
246
    	if (index >0)
247
    	{
248
    		sql = sqlBuff.toString();
249
    	}
250
    	return sql;
251
    }
252

    
253
    /**
254
     * create a String description of the query that this instance represents.
255
     * This should become a way to get the XML serialization of the query.
256
     */
257
    public String toString() {
258
      StringBuffer self = new StringBuffer();
259

    
260
      self.append("  (Query group operator=" + operator + "\n");
261
      Enumeration en= getChildren();
262
      while (en.hasMoreElements()) {
263
        Object qobject = en.nextElement();
264
        self.append(qobject);
265
      }
266
      self.append("  )\n");
267
      return self.toString();
268
    }
269
    
270
    /*
271
     * When a new QueryTerm come, first we need to compare it to
272
     * the queryTerm vector, which contains queryTerm that doesn't
273
     * have same search value to any other queryTerm. Here is algorithm.
274
     * 1) If new QueryTerm find a QueryTerm in queryTerms which has same search value,
275
     *    them create a new vector which contain both QueryTerms and add the new vector
276
     *    to two-dimention vector queryTermsWithSameValue, and remove the QueryTerm which
277
     *    was in queryTerm.
278
     * 2) If new QueryTerm couldn't find a QueryTerm in queryTerms which has same search value,
279
     *    then search queryTermsWithSameValue, to see if this vector already has the search value.
280
     *    2.1) if has the search value, add the new QueryTerm to the queryTermsWithSameValue.
281
     *    2.2) if hasn't, add the new QueryTerm to queryTerms vector.
282
     */
283
    private void handleNewQueryTerms(QueryTerm newTerm)
284
    {
285
    	// currently we only handle UNION group
286
    	if (newTerm != null )
287
    	{
288
    		//System.out.println("new term is not null branch in handle new query term");
289
    		//we only handle union operator now.
290
    		if (operator != null && operator.equalsIgnoreCase(UNION))
291
    	    {
292
    			//System.out.println("in only union branch in handle new query term");
293
	    		for (int i=0; i<queryTerms.size(); i++)
294
	    		{
295
	    			QueryTerm term = (QueryTerm)queryTerms.elementAt(i);
296
	    			if (term != null && term.hasSameSearchValue(newTerm))
297
	    			{
298
	    				//System.out.println("1Move a query term and add a new query term into search value in handle new query term");
299
	    				// find a target which has same search value
300
	    				Vector newSameValueVector = new Vector();
301
	    				newSameValueVector.add(term);
302
	    				newSameValueVector.addElement(newTerm);
303
	    				queryTermsWithSameValue.add(newSameValueVector);
304
	    				queryTerms.remove(i);
305
	    				return;
306
	    			}
307
	    		}
308
	    		// no same search value was found in queryTerms.
309
	    		// then we need search queryTermsWithSameValue
310
	    		for (int i=0; i<queryTermsWithSameValue.size(); i++)
311
	    		{
312
	    			Vector sameValueVec = (Vector)queryTermsWithSameValue.elementAt(i);
313
	    			// we only compare the first query term
314
	    			QueryTerm term = (QueryTerm)sameValueVec.elementAt(0);
315
	    			if (term != null && term.hasSameSearchValue(newTerm))
316
	    			{
317
	    				//System.out.println("2add a new query term into search value in handle new query term");
318
	    				sameValueVec.add(newTerm);
319
	    				return;
320
	    			}
321
	    		}
322
    	    }
323
    		// both queryTerms and queryTermsWithSameValue don't have the search value,
324
    		// add this newTerm to queryTerms
325
    		queryTerms.add(newTerm);
326
    	}
327
    	
328
    }
329
  }
(54-54/67)