テキストブロックからキーワードを抽出する Java ライブラリを探しています。
プロセスは次のようになります。
ストップワードのクリーニング -> ステミング -> 英語の言語学統計情報に基づいたキーワードの検索 - つまり、単語が英語よりもテキスト内で多く出現する確率が高い場合は、それがキーワード候補となります。
このタスクを実行するライブラリはありますか?
ベストアンサー1
ここで考えられる解決策はApache ルシーン最後のバージョンは使用しませんでしたが、3.6.2 1つ、これが私が最もよく知っているものだからです。 のほかに/lucene-core-x.x.x.jar
、ダウンロードしたアーカイブから をプロジェクトに追加することも忘れないでください/contrib/analyzers/common/lucene-analyzers-x.x.x.jar
。これには言語固有のアナライザー (特にあなたの場合は英語のアナライザー) が含まれています。
これはのみ入力テキストの単語の頻度をそれぞれの語幹に基づいて調べます。これらの頻度を英語の統計と比較するのは後で行います(この答えちなみに役に立つかもしれません。
データモデル
1 つの語幹に 1 つのキーワード。異なる単語が同じ語幹を持つ場合があるため、terms
セットになります。キーワードの頻度は、新しい用語が見つかるたびに増加します (すでに見つかっている場合でも、セットによって重複が自動的に削除されます)。
public class Keyword implements Comparable<Keyword> {
private final String stem;
private final Set<String> terms = new HashSet<String>();
private int frequency = 0;
public Keyword(String stem) {
this.stem = stem;
}
public void add(String term) {
terms.add(term);
frequency++;
}
@Override
public int compareTo(Keyword o) {
// descending order
return Integer.valueOf(o.frequency).compareTo(frequency);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (!(obj instanceof Keyword)) {
return false;
} else {
return stem.equals(((Keyword) obj).stem);
}
}
@Override
public int hashCode() {
return Arrays.hashCode(new Object[] { stem });
}
public String getStem() {
return stem;
}
public Set<String> getTerms() {
return terms;
}
public int getFrequency() {
return frequency;
}
}
ユーティリティ
単語の語幹を抽出するには:
public static String stem(String term) throws IOException {
TokenStream tokenStream = null;
try {
// tokenize
tokenStream = new ClassicTokenizer(Version.LUCENE_36, new StringReader(term));
// stem
tokenStream = new PorterStemFilter(tokenStream);
// add each token in a set, so that duplicates are removed
Set<String> stems = new HashSet<String>();
CharTermAttribute token = tokenStream.getAttribute(CharTermAttribute.class);
tokenStream.reset();
while (tokenStream.incrementToken()) {
stems.add(token.toString());
}
// if no stem or 2+ stems have been found, return null
if (stems.size() != 1) {
return null;
}
String stem = stems.iterator().next();
// if the stem has non-alphanumerical chars, return null
if (!stem.matches("[a-zA-Z0-9-]+")) {
return null;
}
return stem;
} finally {
if (tokenStream != null) {
tokenStream.close();
}
}
}
コレクションを検索するには(潜在的なキーワードのリストで使用されます):
public static <T> T find(Collection<T> collection, T example) {
for (T element : collection) {
if (element.equals(example)) {
return element;
}
}
collection.add(example);
return example;
}
芯
主な入力方法は次のとおりです。
public static List<Keyword> guessFromString(String input) throws IOException {
TokenStream tokenStream = null;
try {
// hack to keep dashed words (e.g. "non-specific" rather than "non" and "specific")
input = input.replaceAll("-+", "-0");
// replace any punctuation char but apostrophes and dashes by a space
input = input.replaceAll("[\\p{Punct}&&[^'-]]+", " ");
// replace most common english contractions
input = input.replaceAll("(?:'(?:[tdsm]|[vr]e|ll))+\\b", "");
// tokenize input
tokenStream = new ClassicTokenizer(Version.LUCENE_36, new StringReader(input));
// to lowercase
tokenStream = new LowerCaseFilter(Version.LUCENE_36, tokenStream);
// remove dots from acronyms (and "'s" but already done manually above)
tokenStream = new ClassicFilter(tokenStream);
// convert any char to ASCII
tokenStream = new ASCIIFoldingFilter(tokenStream);
// remove english stop words
tokenStream = new StopFilter(Version.LUCENE_36, tokenStream, EnglishAnalyzer.getDefaultStopSet());
List<Keyword> keywords = new LinkedList<Keyword>();
CharTermAttribute token = tokenStream.getAttribute(CharTermAttribute.class);
tokenStream.reset();
while (tokenStream.incrementToken()) {
String term = token.toString();
// stem each term
String stem = stem(term);
if (stem != null) {
// create the keyword or get the existing one if any
Keyword keyword = find(keywords, new Keyword(stem.replaceAll("-0", "-")));
// add its corresponding initial token
keyword.add(term.replaceAll("-0", "-"));
}
}
// reverse sort by frequency
Collections.sort(keywords);
return keywords;
} finally {
if (tokenStream != null) {
tokenStream.close();
}
}
}
例
このguessFromString
方法を使用するとJava Wikipedia記事紹介部分見つかった最も頻繁なキーワード(語幹)の最初の 10 個は次のとおりです。
java x12 [java]
compil x5 [compiled, compiler, compilers]
sun x5 [sun]
develop x4 [developed, developers]
languag x3 [languages, language]
implement x3 [implementation, implementations]
applic x3 [application, applications]
run x3 [run]
origin x3 [originally, original]
gnu x3 [gnu]
出力リストを反復処理して、どれがオリジナルの単語各語幹について、terms
セットを取得します ([...]
上記の例では括弧内に表示されています)。
次は何ですか
比較する語幹頻度 / 頻度合計英語の統計の比率と、それを管理できた場合は私に知らせてください。私も非常に興味があります:)