Як отримати токен з Lucene TokenStream?


74

Я намагаюся використовувати Apache Lucene для токенізації, і мене бентежить процес отримання токенів у TokenStream.

Найгірше те, що я переглядаю коментарі в JavaDocs, які стосуються мого питання.

http://lucene.apache.org/java/3_0_1/api/core/org/apache/lucene/analysis/TokenStream.html#incrementToken%28%29

Якось AttributeSourceпередбачається використовувати а, а не Tokens. Я абсолютно втрачений.

Хтось може пояснити, як отримати токен-подібну інформацію з TokenStream?

Відповіді:


114

Так, це трохи заплутано (порівняно з добрим старим способом), але це має зробити це:

TokenStream tokenStream = analyzer.tokenStream(fieldName, reader);
OffsetAttribute offsetAttribute = tokenStream.getAttribute(OffsetAttribute.class);
TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);

while (tokenStream.incrementToken()) {
    int startOffset = offsetAttribute.startOffset();
    int endOffset = offsetAttribute.endOffset();
    String term = termAttribute.term();
}

Редагувати: Новий спосіб

За словами Донотелло, TermAttributeбуло припинено на користь CharTermAttribute. Відповідно до jpountz (і документації Люцена), addAttributeбажаніше, ніж getAttribute.

TokenStream tokenStream = analyzer.tokenStream(fieldName, reader);
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);

tokenStream.reset();
while (tokenStream.incrementToken()) {
    int startOffset = offsetAttribute.startOffset();
    int endOffset = offsetAttribute.endOffset();
    String term = charTermAttribute.toString();
}

6
Тепер TermAttribute припинено. Як я бачу, ми можемо використати щось на зразок CharTermAttributeImpl.toString()цього
Донотелло

@Donotello: Щиро дякую за це!
Адам Пейнтер,

6
Вам слід використовувати addAttribute, а не getAttribute. Від lucene javadocs: "Рекомендується завжди використовувати addAttribute (java.lang.Class) навіть у споживачів TokenStreams, оскільки ви не можете знати, чи конкретний TokenStream використовує конкретний атрибут" lucene.apache.org/core/old_versioned_docs/versions / 3_5_0 / api /…
jpountz

1
@jpountz: Дякуємо за підказку! Відповідно я змінив відповідь.
Адам Пейнтер,

2
Довелося зателефонувати reset()з Lucene 4.3, тому взяв на себе свободу додавати його
Enno Shioji

38

Ось як повинно бути (чиста версія відповіді Адама):

TokenStream stream = analyzer.tokenStream(null, new StringReader(text));
CharTermAttribute cattr = stream.addAttribute(CharTermAttribute.class);
stream.reset();
while (stream.incrementToken()) {
  System.out.println(cattr.toString());
}
stream.end();
stream.close();

10
Ваш код не функціонував належним чином, доки я не додав stream.reset () перед циклом while. Я використовую Lucene 4.0, тому це може бути нещодавньою зміною. Зверніться до прикладу внизу цієї сторінки: lucene.apache.org/core/4_0_0-BETA/core/org/apache/lucene/…

Спробував відредагувати, щоб додати виклик reset (), який дозволяє уникнути NPE всередині Lucene за прирістToken (), але всі, крім одного, рівного колега відхилили редагування як неправильне. У документах Lucene чітко сказано, що "Споживач викликає reset ()" перед "Споживачем викликає incrementToken ()" в API TokenStream
Вільям Прайс

Також reset()мені довелося зателефонувати з Lucene 4.3, тому я дозволив його додати
Enno Shioji

можливо, питання дивне, але, нарешті, не дуже зрозуміло, як отримати наступний жетон (не наступний рядок)?
serhio

3

Для останньої версії люцену 7.3.1

    // Test the tokenizer
    Analyzer testAnalyzer = new CJKAnalyzer();
    String testText = "Test Tokenizer";
    TokenStream ts = testAnalyzer.tokenStream("context", new StringReader(testText));
    OffsetAttribute offsetAtt = ts.addAttribute(OffsetAttribute.class);
    try {
        ts.reset(); // Resets this stream to the beginning. (Required)
        while (ts.incrementToken()) {
            // Use AttributeSource.reflectAsString(boolean)
            // for token stream debugging.
            System.out.println("token: " + ts.reflectAsString(true));

            System.out.println("token start offset: " + offsetAtt.startOffset());
            System.out.println("  token end offset: " + offsetAtt.endOffset());
        }
        ts.end();   // Perform end-of-stream operations, e.g. set the final offset.
    } finally {
        ts.close(); // Release resources associated with this stream.
    }

Довідково: https://lucene.apache.org/core/7_3_1/core/org/apache/lucene/analysis/package-summary.html


1

Є два варіанти питання OP:

  1. Що таке "процес отримання токенів з TokenStream"?
  2. "Хтось може пояснити, як отримати токен-подібну інформацію з TokenStream?"

Останні версії документації до Lucene дляToken say (курсив додано):

ПРИМІТКА: Починаючи з 2.9 ... більше не потрібно використовувати Token, з новим API TokenStream його можна використовувати як зручний клас, що реалізує всі атрибути, що особливо корисно для легкого переходу зі старого на новий API TokenStream.

І TokenStreamкаже свій API:

... перейшов із заснування маркера на засіб атрибутів ... найкращим способом зберігання інформації про маркер є використання AttributeImpls.

Інші відповіді на це запитання охоплюють №2 вище: як отримати токеноподібну інформацію з a TokenStream"новим" рекомендованим способом, використовуючи атрибути. Читаючи документацію, розробники Lucene припускають, що ця зміна була внесена, зокрема, для зменшення кількості окремих об’єктів, створених одночасно.

Але, як деякі люди зазначали в коментарях до цих відповідей, вони не відповідають прямо No1: як отримати, Tokenякщо ви справді хочете / потребуєте такого типу?

З таким же зміною API , що робить , тепер знаряддя і може бути використаний з TokenStream.addAttribute так само , як інші відповіді показують на і . Тож вони справді відповіли на цю частину вихідного запитання, просто не показали.TokenStreamAttributeSourceTokenAttributeCharTermAttributeOffsetAttribute

Важливо, що, хоча цей підхід дозволить вам отримати доступ Tokenпід час циклу, це все одно лише один об’єкт, незалежно від того, скільки логічних маркерів знаходиться в потоці. Кожен заклик до incrementToken()змінитиме стан Tokenповернення з addAttribute; Отже, якщо ваша мета - створити колекцію різних Tokenоб’єктів, які будуть використовуватися за межами циклу, вам доведеться виконати додаткову роботу, щоб створити новий Token об’єкт як (глибоку?) Копію.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.