using System; using System.Collections.Concurrent; using System.Collections.Generic; namespace LibSearchBox { public class InvertedIndex { // Gotta be public to allow Newtonsoft.JSON to do it's job. Don't interact with it directly! public ConcurrentDictionary>> invertedIndex = new ConcurrentDictionary>>(); public InvertedIndex() { } public bool AddIndex(int pageId, Index newIndex) { foreach (KeyValuePair> token in newIndex) { if (!invertedIndex.ContainsKey(token.Key) && !invertedIndex.TryAdd(token.Key, new ConcurrentDictionary>())) return false; if (!invertedIndex[token.Key].TryAdd(pageId, token.Value)) return false; } return true; } public bool RemoveIndex(int pageId, Index oldIndex) { foreach (string token in oldIndex.Tokens()) { if (!invertedIndex.ContainsKey(token) || !invertedIndex[token].ContainsKey(pageId)) continue; if (!invertedIndex[token].TryRemove(pageId, out List noop)) return false; } return false; } public bool ReplaceIndex(int pageId, Index oldIndex, Index newIndex) { if (!RemoveIndex(pageId, oldIndex)) return false; if (!AddIndex(pageId, newIndex)) return false; return true; } public bool RemoveById(int pageId) { foreach (KeyValuePair>> pair in invertedIndex) { if (!pair.Value.ContainsKey(pageId)) continue; if (!pair.Value.TryRemove(pageId, out List noop)) return false; if (pair.Value.Count == 0 && !invertedIndex.TryRemove(pair.Key, out var noopAgain)) return false; } return true; } public ConcurrentDictionary> Query(string normalisedToken) { invertedIndex.TryGetValue(normalisedToken, out ConcurrentDictionary> result); return result; } } }