13

I am trying tokenize strings into ngrams. Strangely in the documentation for the NGramTokenizer I do not see a method that will return the individual ngrams that were tokenized. In fact I only see two methods in the NGramTokenizer class that return String Objects.

Here is the code that I have:

Reader reader = new StringReader("This is a test string");
NGramTokenizer gramTokenizer = new NGramTokenizer(reader, 1, 3);
  1. Where are the ngrams that were tokenized?
  2. How can I get the output in Strings/Words?

I want my output to be like: This, is, a, test, string, This is, is a, a test, test string, This is a, is a test, a test string.

CodeKingPlusPlus
  • 15,383
  • 51
  • 135
  • 216

4 Answers4

19

I don't think you'll find what you're looking for trying to find methods returning String. You'll need to deal with Attributes.

Should work something like:

Reader reader = new StringReader("This is a test string");
NGramTokenizer gramTokenizer = new NGramTokenizer(reader, 1, 3);
CharTermAttribute charTermAttribute = gramTokenizer.addAttribute(CharTermAttribute.class);
gramTokenizer.reset();

while (gramTokenizer.incrementToken()) {
    String token = charTermAttribute.toString();
    //Do something
}
gramTokenizer.end();
gramTokenizer.close();

Be sure to reset() the Tokenizer it if it needs to be reused after that, though.


Tokenizing grouping of words, rather than chars, per comments:

Reader reader = new StringReader("This is a test string");
TokenStream tokenizer = new StandardTokenizer(Version.LUCENE_36, reader);
tokenizer = new ShingleFilter(tokenizer, 1, 3);
CharTermAttribute charTermAttribute = tokenizer.addAttribute(CharTermAttribute.class);

while (tokenizer.incrementToken()) {
    String token = charTermAttribute.toString();
    //Do something
}
pnv
  • 1,437
  • 3
  • 23
  • 52
femtoRgon
  • 32,893
  • 7
  • 60
  • 87
  • What can I do with Strings instead of chars in terms of Attributes? So then my output would be something like: This, is, a, test, string, This is, is a, a test, ... a test string. – CodeKingPlusPlus Nov 20 '12 at 23:59
  • 1
    Okay, that's not what Lucene's NGramTokenizer is designed to handle. What you'll want to use, I think, is a ShingleFilter combined with StandardTokenizer. I'll update my answer, easier to express there... – femtoRgon Nov 21 '12 at 00:13
  • Do you know of any stop word filters I can use in the tokenization process? – CodeKingPlusPlus Nov 21 '12 at 00:34
  • I think the standard would be [StopFilter](http://lucene.apache.org/core/3_6_0/api/all/org/apache/lucene/analysis/StopFilter.html). Another very typical filter to apply would be [StandardFilter](http://lucene.apache.org/core/3_6_0/api/all/org/apache/lucene/analysis/standard/StandardFilter.html), by the way. I would think StandardFilter, then StopFilter, then ShingleFilter would probably get good results. – femtoRgon Nov 21 '12 at 16:12
  • Took a look at my latest post involving the StopFilter : http://stackoverflow.com/questions/13501421/java-lucene-stop-words-filter – CodeKingPlusPlus Nov 21 '12 at 20:21
  • Where did tokenStream come from? – rjurney Jan 10 '14 at 04:30
  • @rjurney It must be a typo. It should have been `tokenizer`. – Some guy Feb 06 '14 at 09:07
  • what is your `maven` dependency of lucene NGramTokenizer? – BeeNoisy Aug 07 '19 at 15:15
  • Is there a way I can preserve the spaces as is in the input? For example, for the input `abc xyz mno`, I want `abc xyz` instead of `abc xyz` – Arun Gowda Nov 26 '19 at 01:45
1

For recent version of Lucene (4.2.1), this is a clean code which works. Before executing this code, you have to import 2 jar files:

  • lucene-core-4.2.1.jar
  • lucene-analuzers-common-4.2.1.jar

Find these files at http://www.apache.org/dyn/closer.cgi/lucene/java/4.2.1

//LUCENE 4.2.1
Reader reader = new StringReader("This is a test string");      
NGramTokenizer gramTokenizer = new NGramTokenizer(reader, 1, 3);

CharTermAttribute charTermAttribute = gramTokenizer.addAttribute(CharTermAttribute.class);

while (gramTokenizer.incrementToken()) {
    String token = charTermAttribute.toString();
    System.out.println(token);
}
BSMP
  • 4,596
  • 8
  • 33
  • 44
Amir
  • 21
  • 1
  • 4
0

Without creating a test program, I would guess that incrementToken() returns the next token which will be one of the ngrams.

For example, using ngram lengths of 1-3 with the string 'a b c d', NGramTokenizer could return:

a
a b
a b c
b
b c
b c d
c
c d
d

where 'a', 'a b', etc. are the resulting ngrams.

[Edit]

You might also want to look at Querying lucene tokens without indexing, as it talks about peeking into the token stream.

Community
  • 1
  • 1
Mark Leighton Fisher
  • 5,609
  • 2
  • 18
  • 29
0
package ngramalgoimpl;
import java.util.*;

public class ngr {

    public static List<String> n_grams(int n, String str) {
        List<String> n_grams = new ArrayList<String>();
        String[] words = str.split(" ");
        for (int i = 0; i < words.length - n + 1; i++)
            n_grams.add(concatination(words, i, i+n));
        return n_grams;
    }
     /*stringBuilder is used to cancatinate mutable sequence of characters*/
    public static String concatination(String[] words, int start, int end) {
        StringBuilder sb = new StringBuilder();
        for (int i = start; i < end; i++)
            sb.append((i > start ? " " : "") + words[i]);
        return sb.toString();
    }

    public static void main(String[] args) {
        for (int n = 1; n <= 3; n++) {
            for (String ngram : n_grams(n, "This is my car."))
                System.out.println(ngram);
            System.out.println();
        }
    }
}
Randomize
  • 8,651
  • 18
  • 78
  • 133