source: trunk/gsdl3/src/java/org/greenstone/gsdl3/service/MapQuery.java@ 6490

Last change on this file since 6490 was 6305, checked in by kjdon, 20 years ago

search and retrieve services for the map collection

  • Property svn:keywords set to Author Date Id Revision
File size: 16.2 KB
Line 
1package org.greenstone.gsdl3.service;
2
3// Greenstone classes
4import org.greenstone.gdbm.*;
5import org.greenstone.gsdl3.util.*;
6
7// XML classes
8import org.w3c.dom.Element;
9import org.w3c.dom.Document;
10import org.w3c.dom.NodeList;
11
12// General java classes
13import java.util.Hashtable;
14import java.util.HashMap;
15import java.util.Arrays;
16import java.util.LinkedList;
17import java.lang.reflect.Array;
18import java.util.Comparator;
19import java.io.BufferedReader;
20import java.io.FileReader;
21import java.io.File;
22import java.io.IOException;
23import java.io.ObjectInputStream;
24import java.io.FileInputStream;
25import java.lang.ClassNotFoundException;
26
27/**
28 *
29 *
30 */
31public class MapQuery
32 extends ServiceRack {
33
34 // the services on offer
35 protected static final String MAP_QUERY_SERVICE = "MapQuery";
36
37 // Parameters used - see resources/java/MapQuery.properties
38 protected static final String INDEX_PARAM = "index";
39 protected static final String QUERY_PARAM = "query";
40
41 protected Element config_info_ = null;
42
43 protected String files_home_dir = null;
44
45 protected Element result;
46
47 /** the default index */
48 protected String default_index_ = null;
49
50 // Elements used in the config file that are specific to this class
51 protected static final String DEFAULT_INDEX_ELEM = "defaultIndex";
52 protected static final String INDEX_ELEM = "index"; //
53 protected static final String FREQ_ATT = "freq";
54 protected static final String NUM_DOCS_MATCH_ATT = "numDocsMatch";
55
56 /**
57 * Hashtable containing the LINZ place names database, indexed on the place name in lower case.
58 */
59 public static Hashtable hashNames;
60
61 /** Constructor */
62 public MapQuery() {}
63
64 /** */
65 public boolean configure(Element info, Element extra_info)
66 {
67 System.out.println("Configuring MapQuery...");
68 addExtraQueryInfo(info, extra_info);
69 config_info_ = info;
70
71 // Get the default index out of <defaultIndex> (buildConfig.xml)
72 Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_ELEM);
73 if (def != null) {
74 default_index_ = def.getAttribute(GSXML.NAME_ATT);
75 }
76 if (default_index_ == null || default_index_.equals("")) {
77 System.err.println("Error: default index not specified!");
78 return false;
79 }
80
81 // these entries should reflect the build config file - some services may not be available depending on how the collection was built.
82 // set up short_service_info_ - for now just has id and type. the name (lang dependent) will be added in if the list is requested.
83 Element tq_service = doc.createElement(GSXML.SERVICE_ELEM);
84 tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
85 tq_service.setAttribute(GSXML.NAME_ATT, MAP_QUERY_SERVICE);
86 short_service_info.appendChild(tq_service);
87
88 // set the files_home_dir variable for this collection
89 this.files_home_dir = GSFile.collectionIndexDir(site_home, cluster_name)+File.separator+"assoc"+File.separator;
90
91 // add some format info to service map if there is any
92 Element format = (Element) GSXML.getChildByTagName(info, GSXML.FORMAT_ELEM);
93 if (format != null) {
94 format_info_map.put(MAP_QUERY_SERVICE, doc.importNode(format, true));
95 }
96
97 //load the hashtable
98 hashNames = new Hashtable();
99 try{
100 ObjectInputStream in = new ObjectInputStream(new FileInputStream(this.files_home_dir+"hashnames.dat"));
101 hashNames = (Hashtable)in.readObject();
102 in.close();
103 }catch(IOException ioe){
104 ioe.printStackTrace();
105 }catch(ClassNotFoundException cnf){
106 cnf.printStackTrace();
107 }
108
109 return true;
110 }
111
112 /** */
113 protected Element getServiceDescription(String service, String lang, String subset)
114 {
115 if (service.equals(MAP_QUERY_SERVICE)) {
116
117 Element tq_service = doc.createElement(GSXML.SERVICE_ELEM);
118 tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
119 tq_service.setAttribute(GSXML.NAME_ATT, MAP_QUERY_SERVICE);
120 if (subset==null || subset.equals(GSXML.DISPLAY_TEXT_ELEM)) {
121 tq_service.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_NAME, getTextString(MAP_QUERY_SERVICE+".name", lang)));
122 tq_service.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_SUBMIT, getTextString(MAP_QUERY_SERVICE+".submit", lang)));
123 }
124 if (subset==null || subset.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) {
125 Element param_list = doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
126 createMapQueryParamList(param_list, lang);
127 tq_service.appendChild(param_list);
128 }
129 return tq_service;
130 }
131
132 return null;
133
134 }
135
136 protected boolean addExtraQueryInfo(Element info, Element extra_info){
137
138 if (extra_info == null) {
139 return false;
140 }
141
142 Document owner = info.getOwnerDocument();
143 // so far we have index specific display elements, and global format elements
144 NodeList indexes = info.getElementsByTagName(GSXML.INDEX_ELEM);
145 Element config_search = (Element)GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM);
146
147 for (int i=0; i<indexes.getLength();i++) {
148 Element ind = (Element)indexes.item(i);
149 String name = ind.getAttribute(GSXML.NAME_ATT);
150 Element node_extra = GSXML.getNamedElement(config_search,
151 GSXML.INDEX_ELEM,
152 GSXML.NAME_ATT,
153 name);
154 if (node_extra == null) {
155 System.err.println("MapQuery: haven't found extra info for index named "+name);
156 continue;
157 }
158
159 // get the display elements if any - displayName
160 NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
161 if (display_names !=null) {
162 for (int j=0; j<display_names.getLength(); j++) {
163 Element e = (Element)display_names.item(j);
164 ind.appendChild(owner.importNode(e, true));
165 }
166 }
167 } // for each index
168
169 // get the format element if any
170 Element format = (Element)GSXML.getChildByTagName(config_search,
171 GSXML.FORMAT_ELEM);
172 if (format!=null) { // append to info
173 info.appendChild(owner.importNode(format, true));
174 }
175 return true;
176
177
178 }
179
180 /** creates a new param element and adds it to the param list */
181 protected void createParameter(String name, Element param_list,
182 /*boolean display,*/ String lang)
183 {
184 Element param=null;
185
186 if (name.equals(INDEX_PARAM)) {
187 // the index info - read from config file
188 Element index_list = (Element)GSXML.getChildByTagName(config_info_, INDEX_ELEM+GSXML.LIST_MODIFIER);
189 NodeList indexes = index_list.getElementsByTagName(INDEX_ELEM);
190 int len = indexes.getLength();
191 // now add even if there is only one
192 String [] inds = new String[len];
193 String [] ind_names = new String[len];
194 for (int i=0; i<len; i++) {
195 Element index = (Element)indexes.item(i);
196 inds[i] = index.getAttribute(GSXML.NAME_ATT);
197 ind_names[i] = GSXML.getDisplayText(index, GSXML.DISPLAY_TEXT_NAME, lang, "en");
198
199 }
200 param = GSXML.createParameterDescription(doc, INDEX_PARAM, getTextString("param."+INDEX_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, default_index_, inds, ind_names);
201
202 }
203 else if (name.equals(QUERY_PARAM)) {
204 param = GSXML.createParameterDescription(doc, QUERY_PARAM, getTextString("param."+QUERY_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
205
206 }
207
208 // add the param to the list
209 if (param != null) {
210 param_list.appendChild(param);
211 }
212 }
213
214 /** this creates all the params and appends them to param_list.
215 * if display=true it creates the text strings version
216 * otherwise it creates the description version
217 */
218 protected boolean createMapQueryParamList(Element param_list,
219 String lang)
220 {
221 // the order they are specified here is the order they appear on
222 // the query form
223 //createParameter(INDEX_PARAM, param_list, lang); // doesn't work, so leave it out for now.
224 createParameter(QUERY_PARAM, param_list, lang);
225
226 return true;
227 }
228
229 /** Process a map query */
230 protected Element processMapQuery(Element request)
231 {
232 // Create a new (empty) result message
233 result = doc.createElement(GSXML.RESPONSE_ELEM);
234 result.setAttribute(GSXML.FROM_ATT, MAP_QUERY_SERVICE);
235 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
236
237 // Get the parameters of the request
238 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
239 if (param_list == null) {
240 System.err.println("Error: TextQuery request had no paramList.");
241 return result; // Return the empty result
242 }
243
244 // Process the request parameters
245 HashMap params = GSXML.extractParams(param_list, false);
246
247 // Make sure a query has been specified
248 String searchTerm = (String) params.get(QUERY_PARAM);
249 if (searchTerm == null || searchTerm.equals("")) {
250 return result; // Return the empty result
251 }
252
253 // If an index hasn't been specified, use the default
254 String index = (String) params.get(INDEX_PARAM);
255 if (index == null) {
256 index = default_index_;
257 }
258
259 //convert the query string from the form '&quotTe Awamutu&quot Hamilton' to 'Te Awamutu+Hamilton'
260
261 //replace ' ' with '+'
262 searchTerm = searchTerm.replace(' ','+');
263
264 //replace '&quot' with '"'
265 int place = -1;
266 while(searchTerm.indexOf("&quot;",place+1) != -1){
267 place = searchTerm.indexOf("&quot;",place+1);
268 searchTerm = (searchTerm.substring(0,place) + "\"" + searchTerm.substring(place+6,searchTerm.length()));
269 }
270
271 //replace spaces in string enclosed in quotes
272 place = -1;
273 while(searchTerm.indexOf('"',place+1) != -1){
274 place = searchTerm.indexOf('"',place+1);
275 if(searchTerm.indexOf('"',place+1) != -1)
276 searchTerm = (searchTerm.substring(0,place) + searchTerm.substring(place, searchTerm.indexOf('"',place+1)).replace('+',' ') + searchTerm.substring(searchTerm.indexOf('"',place+1), searchTerm.length()));
277 place = searchTerm.indexOf('"',place);
278 }
279
280 //remove speech marks
281 place = 0;
282 while(place != -1){
283 place = searchTerm.indexOf('"', place);
284 if(place != -1){
285 searchTerm = searchTerm.substring(0, place) + searchTerm.substring(place+1, searchTerm.length());
286 place=0;
287 }
288 }
289
290 //find the number of search terms (number of '+' plus 1)
291 int words = 1;
292 place = 0;
293 while (place != -1){
294 place = searchTerm.indexOf('+', place+1);
295 if(place != -1) words++;
296 }
297 place = 0;
298
299 //store each search term in a string array
300 String terms[] = new String[words];
301 String terms_freq[] = new String[words];
302 for (int i=0; i<(words-1); i++){
303 terms[i]=searchTerm.substring(place, searchTerm.indexOf('+', place));
304 place = searchTerm.indexOf('+', place)+1;
305 }
306 terms[words-1] = searchTerm.substring(place, searchTerm.length());
307
308 Object nameArray[] = new Object[1];
309 int nameArraySize;
310 String nameData;
311 double xco, yco;
312 LinkedList mapList = new LinkedList();
313 LinkedList placeList = new LinkedList();
314 String readString = "";
315
316 //capitalise the search terms
317 for(int i=0;i<words;i++)
318 terms[i] = terms[i].toUpperCase();
319
320 for(int k=0; k<words; k++){
321 nameArraySize=0;
322
323
324 if((nameArray = (Object[])hashNames.get(terms[k].toLowerCase())) != null){
325 //System.out.println(hashNames.get(terms[k].toLowerCase()));
326
327 nameArraySize = Arrays.asList(nameArray).size();
328 }
329
330
331 int h;
332 for(h=0;h<nameArraySize;h++){
333
334 nameData = (String)nameArray[h];
335
336 // get the co-ordinates of the current place name
337 xco = Double.parseDouble(nameData.substring(nameData.lastIndexOf('`')+1,nameData.length()));
338 yco = Double.parseDouble(nameData.substring(nameData.lastIndexOf('`',nameData.lastIndexOf('`')-1)+2,nameData.lastIndexOf('`')));
339
340 //open the text file containing map metadata (first line is a description of the file)
341 try{
342 BufferedReader inmap = new BufferedReader(new FileReader(this.files_home_dir + "files"+File.separator+"maps"+File.separator+"mapdata.txt"));
343 inmap.readLine();
344
345 // for each map
346 while(inmap.ready()){
347 readString = inmap.readLine();
348 int indexer = 0;
349 indexer = readString.indexOf('`')+2;
350 // get the co-ordinates of the top left and bottom right corners of the map.
351 double ytop = Double.parseDouble(readString.substring(indexer,indexer+5));
352 indexer = readString.indexOf('`',indexer)+1;
353 double xtop = Double.parseDouble(readString.substring(indexer,indexer+6));
354 indexer = readString.indexOf('`',indexer)+2;
355 double ybot = Double.parseDouble(readString.substring(indexer,indexer+5));
356 indexer = readString.indexOf('`',indexer)+1;
357 double xbot = Double.parseDouble(readString.substring(indexer,indexer+6));
358
359 //if the place is within the map, put the map metadata and the placename metadata in linked list
360 if(xco >= xtop && xco < xbot && yco >= ytop && yco < ybot)
361 mapList.add(readString+"```"+nameData);
362 }
363 }catch(Exception e){e.printStackTrace();}
364 }
365 }
366
367 // use an array object to sort the linked list by map number
368 Object[] mapListArray = mapList.toArray();
369 Arrays.sort(mapListArray);
370 mapList.clear();
371 for(int mla=0; mla<Array.getLength(mapListArray); mla++)
372 mapList.addFirst(mapListArray[mla]);
373
374 //for each map, create a list of the query matches on that map
375 LinkedList tempList = new LinkedList();
376 String mapNumber = "";
377 String currentMap[] = {"",""};
378 int mapFreq = 0;
379 while(mapList.size()>0){
380 readString = (String)mapList.removeFirst();
381 if(mapNumber.equals(readString.substring(0,readString.indexOf('.')))){
382 currentMap[1] = currentMap[1]+readString.substring(readString.indexOf("```"),readString.length());
383 mapFreq++;
384 }
385 else{
386 if(!currentMap[0].equals(""))
387 tempList.add(currentMap[0]+"`"+mapFreq+currentMap[1]);
388 currentMap[0] = readString.substring(0,readString.indexOf("```"));
389 currentMap[1] = readString.substring(readString.indexOf("```"),readString.length());
390 mapNumber = readString.substring(0,readString.indexOf('.'));
391 mapFreq=1;
392 }
393 }
394 if(!currentMap[0].equals(""))
395 tempList.add(currentMap[0]+"`"+mapFreq+currentMap[1]);
396
397 int totalDocs = tempList.size();
398
399 // use an array object to sort the linked list by number of matches on each map
400 Object[] tempListArray = tempList.toArray();
401 Arrays.sort(tempListArray, new MapResultSorter());
402 tempList.clear();
403 for(int tla=0; tla<Array.getLength(tempListArray); tla++)
404 tempList.add(tempListArray[tla]);
405
406 // Create a metadata list to store information about the query results
407 Element metadata_list = doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
408 result.appendChild(metadata_list);
409
410 // Add a metadata element specifying the number of matching documents
411// Element num_matches_elem = doc.createElement(GSXML.METADATA_ELEM);
412// num_matches_elem.setAttribute(GSXML.NAME_ATT, "numDocsMatched");
413// num_matches_elem.setAttribute(GSXML.VALUE_ATT, "" + totalDocs);
414// result.appendChild(num_matches_elem);
415 GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", "" + totalDocs);
416 GSXML.addMetadata(this.doc, metadata_list, "numDocsReturned", ""+totalDocs);
417 // Create a document list to store the matching documents, and add them
418 Element document_list = doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
419 result.appendChild(document_list);
420 for (int d = 0; d < totalDocs; d++) {
421 String doc_id = (String)tempList.get(d);
422
423 Element doc_node = doc.createElement(GSXML.DOC_NODE_ELEM);
424 doc_node.setAttribute(GSXML.NODE_ID_ATT, doc_id);
425 doc_node.setAttribute(GSXML.NODE_TYPE_ATT, "thumbnail");
426 doc_node.setAttribute(GSXML.DOC_TYPE_ATT, "map");
427 document_list.appendChild(doc_node);
428 }
429
430 // Create a term list to store the term information, and add it
431 Element term_list = doc.createElement(GSXML.TERM_ELEM+GSXML.LIST_MODIFIER);
432 result.appendChild(term_list);
433
434
435 for (int t=0; t<words; t++){
436 String term = terms[t];
437
438 Element term_elem = doc.createElement(GSXML.TERM_ELEM);
439 term_elem.setAttribute(GSXML.NAME_ATT, term);
440 term_elem.setAttribute(FREQ_ATT, "" + terms_freq[t]);
441
442 term_list.appendChild(term_elem);
443 }
444 return result;
445 }
446
447
448 public class MapResultSorter implements Comparator {
449
450 public int compare(Object o1, Object o2) {
451 String first = (String)o1;
452 String second = (String) o2;
453 int firstInt;
454 int secondInt;
455 first = first.substring(first.lastIndexOf('`',first.indexOf("```")-1)+1,first.indexOf("```"));
456 second = second.substring(second.lastIndexOf('`',second.indexOf("```")-1)+1,second.indexOf("```"));
457 firstInt = Integer.parseInt(first);
458 secondInt = Integer.parseInt(second);
459 if(firstInt > secondInt)
460 return -1;
461 else if(firstInt == secondInt)
462 return 0;
463 else
464 return 1;
465 }
466 }
467}
Note: See TracBrowser for help on using the repository browser.