Skip to content

Commit 6ccc532

Browse files
committed
TIKA-4754 -- move to bloom filters for common_tokens
1 parent 67ada35 commit 6ccc532

422 files changed

Lines changed: 404 additions & 453 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

tika-eval/tika-eval-app/src/main/java/org/apache/tika/eval/app/tools/CommonTokenOverlapCounter.java

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,56 +16,84 @@
1616
*/
1717
package org.apache.tika.eval.app.tools;
1818

19-
import java.io.File;
19+
import java.io.BufferedReader;
2020
import java.io.IOException;
21+
import java.nio.charset.StandardCharsets;
22+
import java.nio.file.DirectoryStream;
23+
import java.nio.file.Files;
2124
import java.nio.file.Path;
2225
import java.nio.file.Paths;
2326
import java.util.ArrayList;
27+
import java.util.HashMap;
28+
import java.util.HashSet;
2429
import java.util.List;
2530
import java.util.Locale;
31+
import java.util.Map;
2632
import java.util.Set;
2733

28-
import org.apache.tika.eval.core.tokens.CommonTokenCountManager;
29-
34+
/**
35+
* Dev tool that reports pairs of languages whose common-token lists overlap by more than 1%.
36+
* <p>
37+
* The shipped runtime resources are Bloom filters, which cannot be enumerated, so this reads
38+
* the raw {@code token<TAB>df<TAB>cf} source lists directly. Point it at a directory of those
39+
* files (e.g. {@code tika-eval-core/src/test/resources/common_tokens}).
40+
*/
3041
public class CommonTokenOverlapCounter {
3142

3243
public static void main(String[] args) throws Exception {
3344
Path commonTokensDir = Paths.get(args[0]);
34-
CommonTokenOverlapCounter counter = new CommonTokenOverlapCounter();
35-
counter.execute(commonTokensDir);
45+
new CommonTokenOverlapCounter().execute(commonTokensDir);
3646
}
3747

3848
private void execute(Path commonTokensDir) throws IOException {
39-
List<String> langs = new ArrayList<>();
40-
for (File f : commonTokensDir
41-
.toFile()
42-
.listFiles()) {
43-
langs.add(f.getName());
49+
Map<String, Set<String>> tokensByLang = new HashMap<>();
50+
try (DirectoryStream<Path> ds = Files.newDirectoryStream(commonTokensDir)) {
51+
for (Path p : ds) {
52+
if (Files.isRegularFile(p)) {
53+
tokensByLang.put(p.getFileName().toString(), loadTokens(p));
54+
}
55+
}
4456
}
45-
CommonTokenCountManager mgr = new CommonTokenCountManager(commonTokensDir, "");
57+
List<String> langs = new ArrayList<>(tokensByLang.keySet());
4658
for (int i = 0; i < langs.size() - 1; i++) {
4759
for (int j = i + 1; j < langs.size(); j++) {
48-
compare(langs.get(i), langs.get(j), mgr);
60+
compare(langs.get(i), langs.get(j), tokensByLang);
61+
}
62+
}
63+
}
64+
65+
private static Set<String> loadTokens(Path p) throws IOException {
66+
Set<String> tokens = new HashSet<>();
67+
try (BufferedReader reader = Files.newBufferedReader(p, StandardCharsets.UTF_8)) {
68+
String line;
69+
while ((line = reader.readLine()) != null) {
70+
line = line.trim();
71+
if (line.isEmpty() || line.startsWith("#")) {
72+
continue;
73+
}
74+
String token = line.split("\t", 2)[0].trim();
75+
if (!token.isEmpty()) {
76+
tokens.add(token);
77+
}
4978
}
5079
}
80+
return tokens;
5181
}
5282

53-
private void compare(String langA, String langB, CommonTokenCountManager mgr) {
83+
private void compare(String langA, String langB, Map<String, Set<String>> tokensByLang) {
84+
Set<String> setA = tokensByLang.get(langA);
85+
Set<String> setB = tokensByLang.get(langB);
5486
int overlap = 0;
55-
int denom = 0;
56-
Set<String> setA = mgr.getTokens(langA);
57-
Set<String> setB = mgr.getTokens(langB);
5887
for (String a : setA) {
5988
if (setB.contains(a)) {
6089
overlap += 2;
6190
}
6291
}
63-
denom = setA.size() + setB.size();
92+
int denom = setA.size() + setB.size();
6493
double percent = (double) overlap / (double) denom;
6594
if (percent > 0.01) {
6695
System.out.printf(Locale.US, "%s %s %.2f%n", langA, langB, percent);
6796
}
6897
}
6998

70-
7199
}

tika-eval/tika-eval-core/pom.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
<groupId>commons-codec</groupId>
5656
<artifactId>commons-codec</artifactId>
5757
</dependency>
58+
<dependency>
59+
<groupId>org.apache.commons</groupId>
60+
<artifactId>commons-collections4</artifactId>
61+
</dependency>
5862
<dependency>
5963
<groupId>org.apache.commons</groupId>
6064
<artifactId>commons-math3</artifactId>
@@ -99,8 +103,10 @@
99103
<artifactId>apache-rat-plugin</artifactId>
100104
<configuration>
101105
<inputExcludes>
102-
<inputExclude>src/main/resources/common_tokens/*</inputExclude>
106+
<!-- binary per-language Bloom filters; cannot carry a license header -->
107+
<inputExclude>src/main/resources/common_tokens_bloom/*</inputExclude>
103108
<inputExclude>src/main/resources/*.json</inputExclude>
109+
<!-- raw token lists used only to (re)generate the Bloom filters -->
104110
<inputExclude>src/test/resources/common_tokens/*</inputExclude>
105111
<inputExclude>src/test/resources/test-dirs/**</inputExclude>
106112
</inputExcludes>

tika-eval/tika-eval-core/src/main/java/org/apache/tika/eval/core/textstats/CommonTokens.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818

1919
import java.util.List;
2020
import java.util.Map;
21-
import java.util.Set;
2221

2322
import org.apache.commons.lang3.mutable.MutableInt;
2423
import org.apache.commons.lang3.tuple.Pair;
2524

2625
import org.apache.tika.eval.core.tokens.CommonTokenCountManager;
2726
import org.apache.tika.eval.core.tokens.CommonTokenResult;
2827
import org.apache.tika.eval.core.tokens.LangModel;
28+
import org.apache.tika.eval.core.tokens.TikaEvalTokenizer;
2929
import org.apache.tika.eval.core.tokens.TokenCounts;
3030
import org.apache.tika.language.detect.LanguageResult;
3131

@@ -65,7 +65,9 @@ public CommonTokenResult calculate(List<LanguageResult> languages, TokenCounts t
6565
Pair<String, LangModel> pair =
6666
commonTokenCountManager.getLangTokens(languages.get(0).getLanguage());
6767
String actualLangCode = pair.getKey();
68-
Set<String> commonTokens = pair.getValue().getTokens();
68+
// Membership is via a Bloom filter, so a token not in the common-tokens list may
69+
// very occasionally be counted as common (false positive); never the reverse.
70+
LangModel commonTokens = pair.getValue();
6971
int numUniqueCommonTokens = 0;
7072
int numCommonTokens = 0;
7173
int numUniqueAlphabeticTokens = 0;
@@ -77,7 +79,10 @@ public CommonTokenResult calculate(List<LanguageResult> languages, TokenCounts t
7779
numAlphabeticTokens += count;
7880
numUniqueAlphabeticTokens++;
7981
}
80-
if (commonTokens.contains(token)) {
82+
// Only test tokens that could actually be in a common-token list. A number,
83+
// short token, or HTML term is never in the list, so testing it can only yield a
84+
// (Bloom) false positive; skipping them is a no-op for the exact list.
85+
if (TikaEvalTokenizer.isCommonTokenCandidate(token) && commonTokens.contains(token)) {
8186
numCommonTokens += count;
8287
numUniqueCommonTokens++;
8388
}

tika-eval/tika-eval-core/src/main/java/org/apache/tika/eval/core/textstats/CommonTokensBhattacharyya.java

Lines changed: 0 additions & 58 deletions
This file was deleted.

tika-eval/tika-eval-core/src/main/java/org/apache/tika/eval/core/textstats/CommonTokensCosine.java

Lines changed: 0 additions & 71 deletions
This file was deleted.

tika-eval/tika-eval-core/src/main/java/org/apache/tika/eval/core/textstats/CommonTokensHellinger.java

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)