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-18 11:31:26 -0700 (Wed, 18 Apr 2007) $'
13
 * '$Revision: 3245 $'
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
    	  if (queryString != null)
115
    	  {
116
    		  first = false;
117
    	  }
118
      }
119
      
120
      for (int i=0; i<queryGroupsChildren.size(); i++)
121
      {
122
      
123
        
124
            QueryGroup qg = (QueryGroup)queryGroupsChildren.elementAt(i);
125
        	String queryGroupSQL = qg.printSQL(useXMLIndex);
126
        	logMetacat.info("In QueryGroup.printSQL.. found a QueryGroup: " 
127
        			+ queryGroupSQL);       	
128
        	if (first) {
129
        		first = false;
130
        	} else {
131
        		if(!queryString.toString().equals("") && queryGroupSQL != null &&!queryGroupSQL.equals("")){
132
                    queryString.append(" " + operator + " ");
133
        		}
134
        	}
135
   		  	queryString.append(queryGroupSQL);
136
   		  	
137
   		  	// count percerntage number
138
   		  	int count = qg.getPercentageSymbolCount();
139
   		  	countPercentageSearchItem = countPercentageSearchItem + count;
140
      }
141
      
142
      for (int i=0; i<queryTerms.size(); i++)
143
      {
144
           QueryTerm qt = (QueryTerm)queryTerms.elementAt(i);
145
           String termQueryString = qt.printSQL(useXMLIndex);
146
       	   logMetacat.info("In QueryGroup.printSQL.. found a QueryGroup: " 
147
        			+ termQueryString);
148
           if(!(qt.getSearchMode().equals("contains") && qt.getValue().equals("%"))){
149
        	   if (first) {
150
                   first = false;
151
               } else {
152
                   if(!queryString.toString().equals("")){
153
                       queryString.append(" " + operator + " ");
154
                   }
155
               }
156
               queryString.append(termQueryString);
157
           
158
           // count percerntage number
159
           int count = qt.getPercentageSymbolCount();
160
           countPercentageSearchItem = countPercentageSearchItem + count;
161
        } 
162
      }
163

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

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

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