001: // kelondroMapObjects.java
002: // -----------------------
003: // (C) 29.01.2007 by Michael Peter Christen; mc@anomic.de, Frankfurt a. M., Germany
004: // first published 2004 as part of kelondroMap on http://www.anomic.de
005: //
006: // This is a part of YaCy, a peer-to-peer based web search engine
007: //
008: // $LastChangedDate: 2006-04-02 22:40:07 +0200 (So, 02 Apr 2006) $
009: // $LastChangedRevision: 1986 $
010: // $LastChangedBy: orbiter $
011: //
012: // LICENSE
013: //
014: // This program is free software; you can redistribute it and/or modify
015: // it under the terms of the GNU General Public License as published by
016: // the Free Software Foundation; either version 2 of the License, or
017: // (at your option) any later version.
018: //
019: // This program is distributed in the hope that it will be useful,
020: // but WITHOUT ANY WARRANTY; without even the implied warranty of
021: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
022: // GNU General Public License for more details.
023: //
024: // You should have received a copy of the GNU General Public License
025: // along with this program; if not, write to the Free Software
026: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
027:
028: package de.anomic.kelondro;
029:
030: import java.io.IOException;
031: import java.lang.reflect.InvocationTargetException;
032: import java.lang.reflect.Method;
033: import java.util.HashMap;
034: import java.util.Iterator;
035: import java.util.Map;
036:
037: public class kelondroMapObjects extends kelondroObjects {
038:
039: private String[] sortfields, longaccfields, doubleaccfields;
040: private HashMap<String, kelondroMScoreCluster<String>> sortClusterMap; // a String-kelondroMScoreCluster - relation
041: private HashMap<String, Object> accMap; // to store accumulations of specific fields
042: private int elementCount;
043:
044: public kelondroMapObjects(kelondroDyn dyn, int cachesize) {
045: this (dyn, cachesize, null, null, null, null, null);
046: }
047:
048: @SuppressWarnings("unchecked")
049: public kelondroMapObjects(kelondroDyn dyn, int cachesize,
050: String[] sortfields, String[] longaccfields,
051: String[] doubleaccfields, Method externalInitializer,
052: Object externalHandler) {
053: super (dyn, cachesize);
054:
055: // create fast ordering clusters and acc fields
056: this .sortfields = sortfields;
057: this .longaccfields = longaccfields;
058: this .doubleaccfields = doubleaccfields;
059:
060: kelondroMScoreCluster<String>[] cluster = null;
061: if (sortfields == null)
062: sortClusterMap = null;
063: else {
064: sortClusterMap = new HashMap<String, kelondroMScoreCluster<String>>();
065: cluster = new kelondroMScoreCluster[sortfields.length];
066: for (int i = 0; i < sortfields.length; i++) {
067: cluster[i] = new kelondroMScoreCluster<String>();
068: }
069: }
070:
071: Long[] longaccumulator = null;
072: Double[] doubleaccumulator = null;
073: if ((longaccfields == null) && (doubleaccfields == null)) {
074: accMap = null;
075: } else {
076: accMap = new HashMap<String, Object>();
077: if (longaccfields != null) {
078: longaccumulator = new Long[longaccfields.length];
079: for (int i = 0; i < longaccfields.length; i++) {
080: longaccumulator[i] = new Long(0);
081: }
082: }
083: if (doubleaccfields != null) {
084: doubleaccumulator = new Double[doubleaccfields.length];
085: for (int i = 0; i < doubleaccfields.length; i++) {
086: doubleaccumulator[i] = new Double(0);
087: }
088: }
089: }
090:
091: // fill cluster and accumulator with values
092: if ((sortfields != null) || (longaccfields != null)
093: || (doubleaccfields != null))
094: try {
095: kelondroCloneableIterator<String> it = dyn.dynKeys(
096: true, false);
097: String mapname;
098: Object cell;
099: long valuel;
100: double valued;
101: Map<String, String> map;
102: this .elementCount = 0;
103: while (it.hasNext()) {
104: mapname = it.next();
105: map = getMap(mapname);
106: if (map == null)
107: break;
108:
109: if (sortfields != null)
110: for (int i = 0; i < sortfields.length; i++) {
111: cell = map.get(sortfields[i]);
112: if (cell != null)
113: cluster[i].setScore(mapname,
114: kelondroMScoreCluster
115: .object2score(cell));
116: }
117:
118: if (longaccfields != null)
119: for (int i = 0; i < longaccfields.length; i++) {
120: cell = map.get(longaccfields[i]);
121: valuel = 0;
122: if (cell != null)
123: try {
124: if (cell instanceof Long)
125: valuel = ((Long) cell)
126: .longValue();
127: if (cell instanceof String)
128: valuel = Long
129: .parseLong((String) cell);
130: longaccumulator[i] = new Long(
131: longaccumulator[i]
132: .longValue()
133: + valuel);
134: } catch (NumberFormatException e) {
135: }
136: }
137:
138: if (doubleaccfields != null)
139: for (int i = 0; i < doubleaccfields.length; i++) {
140: cell = map.get(doubleaccfields[i]);
141: valued = 0d;
142: if (cell != null)
143: try {
144: if (cell instanceof Double)
145: valued = ((Double) cell)
146: .doubleValue();
147: if (cell instanceof String)
148: valued = Double
149: .parseDouble((String) cell);
150: doubleaccumulator[i] = new Double(
151: doubleaccumulator[i]
152: .doubleValue()
153: + valued);
154: } catch (NumberFormatException e) {
155: }
156: }
157:
158: if ((externalHandler != null)
159: && (externalInitializer != null)) {
160: try {
161: externalInitializer.invoke(externalHandler,
162: new Object[] { mapname, map });
163: } catch (IllegalArgumentException e) {
164: e.printStackTrace();
165: } catch (IllegalAccessException e) {
166: e.printStackTrace();
167: } catch (InvocationTargetException e) {
168: e.printStackTrace();
169: }
170: }
171: elementCount++;
172: }
173: } catch (IOException e) {
174: }
175:
176: // fill cluster
177: if (sortfields != null)
178: for (int i = 0; i < sortfields.length; i++)
179: sortClusterMap.put(sortfields[i], cluster[i]);
180:
181: // fill acc map
182: if (longaccfields != null)
183: for (int i = 0; i < longaccfields.length; i++)
184: accMap.put(longaccfields[i], longaccumulator[i]);
185: if (doubleaccfields != null)
186: for (int i = 0; i < doubleaccfields.length; i++)
187: accMap.put(doubleaccfields[i], doubleaccumulator[i]);
188: }
189:
190: public void reset() throws IOException {
191: super .reset();
192: if (sortfields == null)
193: sortClusterMap = null;
194: else {
195: sortClusterMap = new HashMap<String, kelondroMScoreCluster<String>>();
196: for (int i = 0; i < sortfields.length; i++) {
197: sortClusterMap.put(sortfields[i],
198: new kelondroMScoreCluster<String>());
199: }
200: }
201:
202: if ((longaccfields == null) && (doubleaccfields == null)) {
203: accMap = null;
204: } else {
205: accMap = new HashMap<String, Object>();
206: if (longaccfields != null) {
207: for (int i = 0; i < longaccfields.length; i++) {
208: accMap.put(longaccfields[i], new Long(0));
209: }
210: }
211: if (doubleaccfields != null) {
212: for (int i = 0; i < doubleaccfields.length; i++) {
213: accMap.put(doubleaccfields[i], new Double(0));
214: }
215: }
216: }
217: this .elementCount = 0;
218: }
219:
220: public synchronized void set(String key,
221: HashMap<String, String> newMap) throws IOException {
222: assert (key != null);
223: assert (key.length() > 0);
224: assert (newMap != null);
225:
226: // update elementCount
227: if ((longaccfields != null) || (doubleaccfields != null)) {
228: final Map<String, String> oldMap = getMap(key, false);
229: if (oldMap == null) {
230: // new element
231: elementCount++;
232: } else {
233: // element exists, update acc
234: if ((longaccfields != null)
235: || (doubleaccfields != null))
236: updateAcc(oldMap, false);
237: }
238: }
239:
240: super .set(key, new kelondroObjectsMapEntry(newMap));
241:
242: // update sortCluster
243: if (sortClusterMap != null)
244: updateSortCluster(key, newMap);
245:
246: // update accumulators with new values (add)
247: if ((longaccfields != null) || (doubleaccfields != null))
248: updateAcc(newMap, true);
249: }
250:
251: private void updateAcc(Map<String, String> map, boolean add) {
252: String value;
253: long valuel;
254: double valued;
255: Long longaccumulator;
256: Double doubleaccumulator;
257: if (longaccfields != null)
258: for (int i = 0; i < longaccfields.length; i++) {
259: value = map.get(longaccfields[i]);
260: if (value != null) {
261: try {
262: valuel = Long.parseLong(value);
263: longaccumulator = (Long) accMap
264: .get(longaccfields[i]);
265: if (add) {
266: accMap.put(longaccfields[i], new Long(
267: longaccumulator.longValue()
268: + valuel));
269: } else {
270: accMap.put(longaccfields[i], new Long(
271: longaccumulator.longValue()
272: - valuel));
273: }
274: } catch (NumberFormatException e) {
275: }
276: }
277: }
278: if (doubleaccfields != null)
279: for (int i = 0; i < doubleaccfields.length; i++) {
280: value = map.get(doubleaccfields[i]);
281: if (value != null) {
282: try {
283: valued = Double.parseDouble(value);
284: doubleaccumulator = (Double) accMap
285: .get(doubleaccfields[i]);
286: if (add) {
287: accMap.put(doubleaccfields[i], new Double(
288: doubleaccumulator.doubleValue()
289: + valued));
290: } else {
291: accMap.put(doubleaccfields[i], new Double(
292: doubleaccumulator.doubleValue()
293: - valued));
294: }
295: } catch (NumberFormatException e) {
296: }
297: }
298: }
299: }
300:
301: private void updateSortCluster(final String key,
302: final Map<String, String> map) {
303: Object cell;
304: kelondroMScoreCluster<String> cluster;
305: for (int i = 0; i < sortfields.length; i++) {
306: cell = map.get(sortfields[i]);
307: if (cell != null) {
308: cluster = (kelondroMScoreCluster<String>) sortClusterMap
309: .get(sortfields[i]);
310: cluster.setScore(key, kelondroMScoreCluster
311: .object2score(cell));
312: sortClusterMap.put(sortfields[i], cluster);
313: }
314: }
315: }
316:
317: public synchronized void remove(String key) throws IOException {
318: if (key == null)
319: return;
320:
321: // update elementCount
322: if ((sortfields != null) || (longaccfields != null)
323: || (doubleaccfields != null)) {
324: final Map<String, String> map = getMap(key);
325: if (map != null) {
326: // update count
327: elementCount--;
328:
329: // update accumulators (subtract)
330: if ((longaccfields != null)
331: || (doubleaccfields != null))
332: updateAcc(map, false);
333:
334: // remove from sortCluster
335: if (sortfields != null)
336: deleteSortCluster(key);
337: }
338: }
339: super .remove(key);
340: }
341:
342: public HashMap<String, String> getMap(String key) {
343: try {
344: kelondroObjectsMapEntry mapEntry = (kelondroObjectsMapEntry) super
345: .get(key);
346: if (mapEntry == null)
347: return null;
348: return mapEntry.map();
349: } catch (IOException e) {
350: e.printStackTrace();
351: return null;
352: }
353: }
354:
355: protected Map<String, String> getMap(String key, boolean cache) {
356: try {
357: kelondroObjectsMapEntry mapEntry = (kelondroObjectsMapEntry) super
358: .get(key, cache);
359: if (mapEntry == null)
360: return null;
361: return mapEntry.map();
362: } catch (IOException e) {
363: e.printStackTrace();
364: return null;
365: }
366: }
367:
368: private void deleteSortCluster(final String key) {
369: if (key == null)
370: return;
371: kelondroMScoreCluster<String> cluster;
372: for (int i = 0; i < sortfields.length; i++) {
373: cluster = sortClusterMap.get(sortfields[i]);
374: cluster.deleteScore(key);
375: sortClusterMap.put(sortfields[i], cluster);
376: }
377: }
378:
379: public synchronized Iterator<String> keys(final boolean up, /* sorted by */
380: String field) {
381: // sorted iteration using the sortClusters
382: if (sortClusterMap == null)
383: return null;
384: final kelondroMScoreCluster<String> cluster = sortClusterMap
385: .get(field);
386: if (cluster == null)
387: return null; // sort field does not exist
388: //System.out.println("DEBUG: cluster for field " + field + ": " + cluster.toString());
389: return cluster.scores(up);
390: }
391:
392: public synchronized mapIterator maps(final boolean up,
393: final String field) {
394: return new mapIterator(keys(up, field));
395: }
396:
397: public synchronized mapIterator maps(final boolean up,
398: final boolean rotating) throws IOException {
399: return new mapIterator(keys(up, rotating));
400: }
401:
402: public synchronized mapIterator maps(final boolean up,
403: final boolean rotating, final byte[] firstKey,
404: final byte[] secondKey) throws IOException {
405: return new mapIterator(keys(up, rotating, firstKey, secondKey));
406: }
407:
408: public synchronized long getLongAcc(final String field) {
409: final Long accumulator = (Long) accMap.get(field);
410: if (accumulator == null)
411: return -1;
412: return accumulator.longValue();
413: }
414:
415: public synchronized double getDoubleAcc(final String field) {
416: final Double accumulator = (Double) accMap.get(field);
417: if (accumulator == null)
418: return -1;
419: return accumulator.doubleValue();
420: }
421:
422: public synchronized int size() {
423: if ((sortfields != null) || (longaccfields != null)
424: || (doubleaccfields != null))
425: return elementCount;
426: return super .size();
427: }
428:
429: public void close() {
430: // close cluster
431: if (sortClusterMap != null) {
432: for (int i = 0; i < sortfields.length; i++)
433: sortClusterMap.remove(sortfields[i]);
434: sortClusterMap = null;
435: }
436:
437: super .close();
438: }
439:
440: public class mapIterator implements
441: Iterator<HashMap<String, String>> {
442: // enumerates Map-Type elements
443: // the key is also included in every map that is returned; it's key is 'key'
444:
445: Iterator<String> keyIterator;
446: boolean finish;
447:
448: public mapIterator(Iterator<String> keyIterator) {
449: this .keyIterator = keyIterator;
450: this .finish = false;
451: }
452:
453: public boolean hasNext() {
454: return (!(finish)) && (keyIterator != null)
455: && (keyIterator.hasNext());
456: }
457:
458: public HashMap<String, String> next() {
459: String nextKey;
460: HashMap<String, String> map;
461: while (keyIterator.hasNext()) {
462: nextKey = keyIterator.next();
463: if (nextKey == null) {
464: finish = true;
465: return null;
466: }
467: map = getMap(nextKey);
468: if (map == null)
469: continue; // circumvention of a modified exception
470: map.put("key", nextKey);
471: return map;
472: }
473: throw new kelondroException("no more elements available");
474: }
475:
476: public void remove() {
477: throw new UnsupportedOperationException();
478: }
479: } // class mapIterator
480: }
|