transient sclass DeepWordIndex { S regexp = "\\w+"; new Map entries; MultiSetMap entriesByWord = ciMap(); sclass Entry { A id; Map wordPositions = ciMap(); *(A *id) {} } L wordRanges(S text) { ret regexpFindRanges(regexp, text); } void add(A a, S text) { Entry e = entries.get(a); if (e == null) entries.put(a, new Entry(a)); for (IntRange r : wordRanges(text)) { S word = substring(text, r); e.wordPositions.put(word, r.start); entriesByWord.put(word, e); } } }