4

こんにちは私は32MBのファイルを持っています。これは、280万行を含む1250でエンコードされた単純な辞書ファイルです。すべての行には、一意の単語が1つだけあります。

cat
dog
god
...

Luceneを使用して、特定の単語の辞書にあるすべてのアナグラムを検索したいと思います。例えば:

という単語のすべてのアナグラムを検索したいのですが、luceneは私の辞書を検索して、を返す必要があります。私のウェブアプリにはWordエンティティがあります:

public class Word {
    private Long id;
    private String word;
    private String baseLetters;
    private String definition;
}

baseLettersは、そのようなアナグラムを検索するためにアルファベット順に並べ替えられた変数です[神と犬の単語は同じbaseLetters:dgoを持ちます]。別のサービスでこのbaseLetters変数を使用して、データベースからこのようなアナグラムを検索することに成功しましたが、辞書ファイルのインデックスを作成するのに問題があります。フィールドに追加する必要があることはわかっています。

wordとbaseLettersですが、その方法がわかりません:(誰かがこの目標を達成するための方向性を教えてくれませんか?

今のところ私はそのようなものしか持っていません:

public class DictionaryIndexer {

private static final Logger logger = LoggerFactory.getLogger(DictionaryIndexer.class);

@Value("${dictionary.path}")
private String dictionaryPath;

@Value("${lucene.search.indexDir}")
private String indexPath;

public void createIndex() throws CorruptIndexException, LockObtainFailedException {
    try {
        IndexWriter indexWriter = getLuceneIndexer();
        createDocument();           
    } catch (IOException e) {
        logger.error(e.getMessage(), e);
    }       
 }

private IndexWriter getLuceneIndexer() throws CorruptIndexException, LockObtainFailedException, IOException {
    StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
    indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
    Directory directory = new SimpleFSDirectory(new File(indexPath));
    return new IndexWriter(directory, indexWriterConfig);
}

private void createDocument() throws FileNotFoundException {
    File sjp = new File(dictionaryPath);
    Reader reader = new FileReader(sjp);

    Document dictionary = new Document();
    dictionary.add(new Field("word", reader));
}

}

PS:もう1つ質問があります。SpringでDocumentIndexerをBeanとして登録すると、Webアプリを再デプロイするたびにインデックスが作成/追加されますか?同じことが将来のDictionarySearcherにも当てはまりますか?

4

2 に答える 2

8

Luceneは、検索を実行していないため、これに最適なツールではありません。ルックアップを実行しているからです。実際の作業はすべて「インデクサー」で行われ、すべての作業の結果を保存するだけです。ルックアップは、任意のハッシュタイプのストレージメカニズムでO(1)にすることができます。

インデクサーが行うべきことは次のとおりです。

  1. SortedSet辞書全体を、またはのような単純な構造に読み込みますString[]
  2. 結果を保存するための空HashMap<String,List<String>>(おそらくパフォーマンスのために同じサイズ)を作成します
  3. 辞書をアルファベット順に繰り返します(実際にはどの順序でも機能します。すべてのエントリをヒットするようにしてください)
    1. 単語内の文字を並べ替える
    2. ストレージコレクションでソートされた文字を検索します
    3. ルックアップが成功した場合は、現在の単語をリストに追加します。それ以外の場合は、単語を含む新しいリストを作成し、ストレージに配置しますMap
  4. 後でこのマップが必要になった場合は、マップをディスクに保存してください。それ以外の場合は、メモリに保持します
  5. 辞書を破棄する

ルックアッププロセスで行うべきことは次のとおりです。

  1. サンプル単語の文字を並べ替える
  2. ストレージコレクションでソートされた文字を検索します
  3. List出力からサンプル単語を省略するように注意しながら、ルックアップ(またはnull)から戻ってくるを印刷します

ヒープスペースを節約したい場合は、DAWGの使用を検討してください。32MiBではなく、数百キロバイトで英語の単語の辞書全体を表すことができることがわかります。読者の練習問題として残しておきます。

宿題を頑張ってください。

于 2012-12-28T16:35:19.840 に答える
4

関数createDocument()は次のようになります

private void createDocument() throws FileNotFoundException {
    File sjp = new File(dictionaryPath);
    BufferedReader reader = new BufferedReader(new FileReader(sjp));

    String readLine = null;
    while((readLine = reader.readLine() != null)) {
        readLine = readLine.trim();
        Document dictionary = new Document();
        dictionary.add(new Field("word", readLine));
        // toAnagram methods sorts the letters in the word. Also makes it
        // case insensitive.
        dictionary.add(new Field("anagram", toAnagram(readLine)));
        indexWriter.addDocument(dictionary);
    }
}

Luceneを多くの機能に使用している場合は、Lucene上に構築された検索プラットフォームであるApacheSolrの使用を検討してください。

アナグラムグループごとに1つのエントリだけでインデックスをモデル化することもできます。

{"anagram" : "scare", "words":["cares", "acres"]}
{"anagram" : "shoes", "words":["hoses"]}
{"anagram" : "spore", "words":["pores", "prose", "ropes"]}

これには、辞書ファイルの処理中にインデックス内の既存のドキュメントを更新する必要があります。このような場合、Solrはより高いレベルのAPIを支援します。たとえば、IndexWriterはドキュメントの更新をサポートしていません。Solrは更新をサポートしています。

このようなインデックスは、アナグラム検索ごとに1つの結果ドキュメントを提供します。

それが役に立てば幸い。

于 2013-01-01T11:11:36.777 に答える