Skip to content

Commit 0b1cacc

Browse files
authored
Determinize Automaton for simple_pattern and simple_pattern_split tokenizer (opensearch-project#20350)
Signed-off-by: Mohit Godwani <mgodwan@amazon.com>
1 parent 66d2482 commit 0b1cacc

3 files changed

Lines changed: 63 additions & 6 deletions

File tree

modules/analysis-common/src/main/java/org/opensearch/analysis/common/SimplePatternSplitTokenizerFactory.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,27 @@
3434

3535
import org.apache.lucene.analysis.Tokenizer;
3636
import org.apache.lucene.analysis.pattern.SimplePatternSplitTokenizer;
37+
import org.apache.lucene.util.automaton.Automaton;
38+
import org.apache.lucene.util.automaton.Operations;
39+
import org.apache.lucene.util.automaton.RegExp;
3740
import org.opensearch.common.settings.Settings;
3841
import org.opensearch.env.Environment;
3942
import org.opensearch.index.IndexSettings;
4043
import org.opensearch.index.analysis.AbstractTokenizerFactory;
4144

4245
public class SimplePatternSplitTokenizerFactory extends AbstractTokenizerFactory {
4346

44-
private final String pattern;
47+
private final Automaton dfa;
4548

4649
public SimplePatternSplitTokenizerFactory(IndexSettings indexSettings, Environment environment, String name, Settings settings) {
4750
super(indexSettings, settings, name);
4851

49-
pattern = settings.get("pattern", "");
52+
final String pattern = settings.get("pattern", "");
53+
this.dfa = Operations.determinize(new RegExp(pattern).toAutomaton(), Operations.DEFAULT_DETERMINIZE_WORK_LIMIT);
5054
}
5155

5256
@Override
5357
public Tokenizer create() {
54-
return new SimplePatternSplitTokenizer(pattern);
58+
return new SimplePatternSplitTokenizer(dfa);
5559
}
5660
}

modules/analysis-common/src/main/java/org/opensearch/analysis/common/SimplePatternTokenizerFactory.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,27 @@
3434

3535
import org.apache.lucene.analysis.Tokenizer;
3636
import org.apache.lucene.analysis.pattern.SimplePatternTokenizer;
37+
import org.apache.lucene.util.automaton.Automaton;
38+
import org.apache.lucene.util.automaton.Operations;
39+
import org.apache.lucene.util.automaton.RegExp;
3740
import org.opensearch.common.settings.Settings;
3841
import org.opensearch.env.Environment;
3942
import org.opensearch.index.IndexSettings;
4043
import org.opensearch.index.analysis.AbstractTokenizerFactory;
4144

4245
public class SimplePatternTokenizerFactory extends AbstractTokenizerFactory {
4346

44-
private final String pattern;
47+
private final Automaton dfa;
4548

4649
public SimplePatternTokenizerFactory(IndexSettings indexSettings, Environment environment, String name, Settings settings) {
4750
super(indexSettings, settings, name);
4851

49-
pattern = settings.get("pattern", "");
52+
final String pattern = settings.get("pattern", "");
53+
this.dfa = Operations.determinize(new RegExp(pattern).toAutomaton(), Operations.DEFAULT_DETERMINIZE_WORK_LIMIT);
5054
}
5155

5256
@Override
5357
public Tokenizer create() {
54-
return new SimplePatternTokenizer(pattern);
58+
return new SimplePatternTokenizer(dfa);
5559
}
5660
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.analysis.common;
10+
11+
import org.apache.lucene.analysis.Tokenizer;
12+
import org.opensearch.common.settings.Settings;
13+
import org.opensearch.core.index.Index;
14+
import org.opensearch.test.IndexSettingsModule;
15+
import org.opensearch.test.OpenSearchTokenStreamTestCase;
16+
17+
import java.io.IOException;
18+
import java.io.StringReader;
19+
20+
public class SimplePatternTokenizerTests extends OpenSearchTokenStreamTestCase {
21+
22+
public void testComplexRegexRequiringDeterminization() throws IOException {
23+
Settings settings = Settings.builder().put("pattern", "(a+|b+)*c").build();
24+
SimplePatternTokenizerFactory factory = new SimplePatternTokenizerFactory(
25+
IndexSettingsModule.newIndexSettings(new Index("test", "_na_"), Settings.EMPTY),
26+
null,
27+
"test",
28+
settings
29+
);
30+
31+
Tokenizer tokenizer = factory.create();
32+
tokenizer.setReader(new StringReader("aaac bbbbc ac"));
33+
assertTokenStreamContents(tokenizer, new String[] { "aaac", "bbbbc", "ac" });
34+
}
35+
36+
public void testComplexRegexRequiringDeterminizationSplit() throws IOException {
37+
Settings settings = Settings.builder().put("pattern", "(\\s+|,+)*").build();
38+
SimplePatternSplitTokenizerFactory factory = new SimplePatternSplitTokenizerFactory(
39+
IndexSettingsModule.newIndexSettings(new Index("test", "_na_"), Settings.EMPTY),
40+
null,
41+
"test",
42+
settings
43+
);
44+
45+
Tokenizer tokenizer = factory.create();
46+
tokenizer.setReader(new StringReader("word1 word2,,,word3"));
47+
assertTokenStreamContents(tokenizer, new String[] { "word1", "word2", "word3" });
48+
}
49+
}

0 commit comments

Comments
 (0)