sclass TripleIndex extends VirtualNodeIndex { static bool useExactIndex; // experimental bool activated; // are we the main index (see tripleIndex()) // index of word in any position - not used anymore SyncListMultiMap index;// = symbolSyncListMultiMap(); // count per word MultiSet wordIndex = //caseInsensitiveCompactMultiSet(); // not a NavigableMap caseInsensitiveMultiSet(); // word in position SyncListMultiMap[] positionalIndices = new SyncListMultiMap[] { symbolSyncListMultiMap(), symbolSyncListMultiMap(), symbolSyncListMultiMap() }; // all three words ExactTripleIndex exactIndex = useExactIndex ? exactTripleIndex() : null; // triples by ID new CompactHashSet websByID; // first word -> relation -> triple Map> oneTwoIndex; // = (Map) symbolMap(); // SyncListMultiMap, TripleWeb> oneTwoIndex2 = new SyncListMultiMap; // works, but wastes space SyncListMultiMap, TripleWeb> oneTwoIndex2 = new SyncListMultiMap(new CompactPairKeyHashMap); // try compact version int size() { ret numWebs(); } int numWebs() { ret l(websByID); } int numTerms() { ret index != null ? index.keysSize() : wordIndex.uniqueSize(); } Set mainKeys() { ret index != null ? keys(index) : wordIndex.asSet(); } NavigableSet navigableMainKeys() { ret index != null ? navigableKeys(index) : wordIndex.navigableSet(); } // for synchronizing, e.g. in fullIndexedTermsStartingWith Map mainIndexMap() { ret index != null ? index.data : wordIndex.map; } Collection indexedTerms() { ret mainKeys(); } // query is shortened term L get(CharSequence _query) { Symbol query = symbol(_query); L triples = index != null ? index.get(query) : combineLists3(getTriples(query, 0), getTriples(query, 1), getTriples(query, 2)); ret ai_triplesToWebNodes_lazyList(query, triples); } // terms are NOT shortened /*TripleWeb getExact(Symbol a, Symbol b, Symbol c) { if (exactIndex == null) null; ret exactIndex.find(dummyTripleWebWithEntries(a, b, c)); }*/ // query is shortened term L> getTripleRefs(Symbol query) { if (index == null) fail("no index"); ret ai_triplesToTripleRefs_lazyList(query, index.get(query)); } L> getTripleRefs(Symbol query, int position) { ret ai_triplesToTripleRefs_lazyList(query, getTriples(query, position)); } // query is shortened term L getTriples(Symbol query) { if (index == null) fail("no index"); ret index.get(query); } // query is shortened term L getTriples(Symbol query, int position) { ret positionalIndices[position].get(query); } bool hasShortTerm(Symbol s) { ret index != null ? index.containsKey(s) : wordIndex.contains(s); } Web getWeb(GlobalID id) { ret webFromTriple(getTriple(id)); } TripleWeb getTriple(GlobalID id) { ret websByID.find(dummyTripleWebWithGlobalID(id)); } void addWeb(Web web) { if (web == null) ret; TripleWeb w = ai_webToTripleWeb(web); if (w == null) fail("Skipping non-tripelizable web: " + webToStringShort(web)); addTriple(w); } void addTriple(TripleWeb w) { if (w == null) ret; if (index != null) for (Symbol s : sortedInPlace(ll(w.a, w.b, w.c))) index.put(s, w); if (wordIndex != null) { wordIndex.add(w.a); wordIndex.add(w.b); wordIndex.add(w.c); } positionalIndices[0].put(w.a, w); positionalIndices[1].put(w.b, w); positionalIndices[2].put(w.c, w); if (exactIndex != null) exactIndex.add(w); if (oneTwoIndex != null) synchronized(oneTwoIndex) { SyncListMultiMap map = oneTwoIndex.get(w.a); if (map == null) oneTwoIndex.put(w.a, map = symbolSyncListMultiMap()); map.put(w.b, w); } if (oneTwoIndex2 != null) oneTwoIndex2.put(pair(w.a, w.b), w); websByID.add(w); if (activated) ai_fireNewTriple(w); } void removeWeb(Web web) { if (web != null) removeTriple(ai_webToTripleWeb(web)); } void removeTriples(Collection l) { new MultiMap mm; for (TripleWeb w : l) { mm.put(ai_shortenForIndex(w.a), w); mm.put(ai_shortenForIndex(w.b), w); mm.put(ai_shortenForIndex(w.c), w); removeFromSets(w); } for (Symbol term : keys(mm)) { HashSet webs = asHashSet(mm.get(term)); if (index != null) indexRemoveMulti(index, term, webs); for i to 3: indexRemoveMulti(positionalIndices[i], term, webs); } if (activated) for (TripleWeb w : l) ai_fireForgottenTriple(w); } // internal void removeFromSets(TripleWeb w) { websByID.remove(w); if (exactIndex != null) exactIndex.remove(w); if (oneTwoIndex != null) synchronized(oneTwoIndex) { SyncListMultiMap map = oneTwoIndex.get(w.a); if (map != null) { map.remove(w.a, w); if (empty(map)) oneTwoIndex.remove(w.a); } } if (oneTwoIndex2 != null) oneTwoIndex2.remove(pair(w.a, w.b), w); if (wordIndex != null) { wordIndex.remove(w.a); wordIndex.remove(w.b); wordIndex.remove(w.c); } } void removeTriple(TripleWeb w) { if (w == null) ret; removeFromSets(w); GlobalID id = w.globalID(); indexRemove(0, ai_shortenForIndex(w.a), id); indexRemove(1, ai_shortenForIndex(w.b), id); indexRemove(2, ai_shortenForIndex(w.c), id); if (activated) ai_fireForgottenTriple(w); } // internal void indexRemove(int position, Symbol term, GlobalID globalID) { if (index != null) indexRemove2(index, term, globalID); indexRemove2(positionalIndices[position], term, globalID); } // remove from a single list void indexRemove2(MultiMap mm, Symbol term, GlobalID globalID) { L l = mm.get(term); for i over l: if (eq(l.get(i).globalID(), globalID)) { mm.remove(term, l.get(i)); ret; } } // internal void indexRemoveMulti(MultiMap mm, Symbol term, Set set) { L l = mm.get(term); synchronized(l) { removeSetFromListQuickly(l, set); } } void clear() { if (index != null) index.clear(); if (wordIndex != null) wordIndex.clear(); websByID.clear(); if (exactIndex != null) exactIndex.clear(); if (oneTwoIndex != null) oneTwoIndex.clear(); if (oneTwoIndex2 != null) oneTwoIndex2.clear(); } void activate { if (!activated) { activated = true; ai_onNewOrRemovedWeb(func(Web web) { addWeb(web); false; }, func(Web web) { removeWeb(web); false; }); } } Collection allTriples() { ret websByID; } void trimToSize() { if (index != null) trimToSizeAll(index.allLists()); for i to 3: trimToSizeAll(positionalIndices[i].allLists()); for (SyncListMultiMap map : values(oneTwoIndex)) trimToSizeAll(map.allLists()); } void sortAllLists() { if (index != null) sortLists(index.allLists()); for i to 3: sortLists(positionalIndices[i].allLists()); for (SyncListMultiMap map : values(oneTwoIndex)) sortLists(map.allLists()); } void sortLists(Collection> ll) { for (L l : ll) ai_sortTriplesListByPriority_inPlace(l); } L getOneTwo(Symbol a, Symbol b) { if (oneTwoIndex2 != null) ret oneTwoIndex2.get(pair(a, b)); ret shortestList2(getTriples(a), getTriples(b)); } }