2012-03-23 15 views
1

特定のディレクトリにあるインデックスを使用する方法があります。特定の状況で同期とIOファイル

public class TestSearchEngine implements SearchEngine<Tag> { 

private static final String INDEX_PATH = "/test/index"; 

private Directory directory; 
@Inject private TagDAO tagDAO; 
private int organizationId; 

@Override 
public void add(Tag tag) { 
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35));   
    IndexWriter indexWriter = getIndexWriter(indexWriterConfig); 

    //Create document 
    Document document = new Document(); 
    document.add(new Field("id", String.valueOf(tag.getId()), Field.Store.YES, Field.Index.NOT_ANALYZED)); 
    document.add(new Field("title", tag.getTitle(), Field.Store.NO, Field.Index.ANALYZED)); 

    try { 
     indexWriter.addDocument(document); 
     indexWriter.close(); 
    } catch (CorruptIndexException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

@Override 
public synchronized void setDirectory(int organizationId) throws IOException { 
    this.organizationId = organizationId; 
    File path = new File(INDEX_PATH + "/" + String.valueOf(organizationId)); 

    //If path does not exist, create it and create new index for organization 
    if(!path.exists()) { 
     path.mkdirs(); 
     buildCompleteIndex(organizationId, false); 
    } 

    this.directory = FSDirectory.open(path); //Open directory 
} 

private void buildCompleteIndex(int organizationId, boolean rebuildDir) { 
    if(rebuildDir) { 
     File path = new File(INDEX_PATH + "/" + String.valueOf(organizationId)); 
     try { 
      Utils.deleteDirectory(path); 
     } catch (IOException e) { 
      throw new LuceneIndexException("Error rebuilding index directory.", e); 
     } 
     path.mkdirs(); 
    } 

    List<Tag> tagList = tagDAO.findAll(organizationId); 
    for(Tag tag : tagList) { 
     add(tag); 
    } 
} 

private IndexReader getIndexReader() { 
    try { 
     return IndexReader.open(directory); 
    } catch (CorruptIndexException e) { 
     buildCompleteIndex(organizationId, true); 
    } catch (IOException e) { 
     throw new LuceneIndexException("IOException prevented IndexReader from opening Index.", e); 
    } catch(NullPointerException e) { 
     throw new LuceneIndexException("Index resource not available.", e); 
    } 
    return null; 
} 

}

インデックスが破損、またはそれは単にまだ作成されていないされている何らかの理由であれば、私は例外をキャッチします。その場合、ディレクトリを削除し、データソースからインデックスを再作成するbuildCompleteIndex()メソッドが呼び出されます。

マルチスレッド環境では、クラスのインスタンスを作成し、削除または再構築中にディレクトリを呼び出すメソッドを使用して別のスレッドから保護するにはどうすればよいですか?他のメソッドが動作する前にsetDirectory()メソッドを呼び出さなければならないので、このメソッドで同期を設定するとこれを解決すると仮定しますが、スレッドが既に存在する間にディレクトリが破損した場合、同時に方法?言い換えれば、私は、マルチスレッド環境でIOファイルを削除して更新する正しい方法についてちょっと混乱しています。いくつかのアドバイスをいただければ幸いです。

答えて

0

コードを確認すると、setDirectory()で同期しています。その特定のインスタンスを使用するすべてのスレッドについて、そのメソッドが完了するまでブロックされます。これにはbuildCompleteIndexが含まれます。このクラスの新しいインスタンスを作成するスレッドがある場合は、他のものと同期する必要があります。たとえば、静的インスタンスに対して同期することができます。

特に、複数の環境(JDKなど)を実行している場合、ファイルやフォルダの同期は非常に複雑になります。

私はあなたの問題を理解していた場合、次のような何かがうまくいくかもしれない:異なるスレッドから同じインスタンスを使用可能な場合はあなたがそう

public class TestSearchEngine implements SearchEngine<Tag> { 

private static final String INDEX_PATH = "/test/index"; 

private Directory directory; 
@Inject private TagDAO tagDAO; 
private int organizationId; 

private static final Object mutex = new Object(); 

@Override 
public void add(Tag tag) { 
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35));   
    IndexWriter indexWriter = getIndexWriter(indexWriterConfig); 

    //Create document 
    Document document = new Document(); 
    document.add(new Field("id", String.valueOf(tag.getId()), Field.Store.YES, Field.Index.NOT_ANALYZED)); 
    document.add(new Field("title", tag.getTitle(), Field.Store.NO, Field.Index.ANALYZED)); 

    try { 
     indexWriter.addDocument(document); 
     indexWriter.close(); 
    } catch (CorruptIndexException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

@Override 
public void setDirectory(int organizationId) throws IOException { 

     synchronized (mutex) { 
     this.organizationId = organizationId; 
     File path = new File(INDEX_PATH + "/" + String.valueOf(organizationId)); 

     //If path does not exist, create it and create new index for organization 
     if(!path.exists()) { 
      path.mkdirs(); 
      buildCompleteIndex(organizationId, false); 
     } 

     this.directory = FSDirectory.open(path); //Open directory 
     } 
} 

private void buildCompleteIndex(int organizationId, boolean rebuildDir) { 
    if(rebuildDir) { 
     File path = new File(INDEX_PATH + "/" + String.valueOf(organizationId)); 
     try { 
      Utils.deleteDirectory(path); 
     } catch (IOException e) { 
      throw new LuceneIndexException("Error rebuilding index directory.", e); 
     } 
     path.mkdirs(); 
    } 

    List<Tag> tagList = tagDAO.findAll(organizationId); 
    for(Tag tag : tagList) { 
     add(tag); 
    } 
} 

private IndexReader getIndexReader() { 
    try { 
     return IndexReader.open(directory); 
    } catch (CorruptIndexException e) { 
     buildCompleteIndex(organizationId, true); 
    } catch (IOException e) { 
     throw new LuceneIndexException("IOException prevented IndexReader from opening Index.", e); 
    } catch(NullPointerException e) { 
     throw new LuceneIndexException("Index resource not available.", e); 
    } 
    return null; 
} 
+0

私は理解できます。ミューテックスオブジェクトのポイントは何ですか?どのように動作するか説明できますか? – ryandlf

+0

あなたは何か共通のものを持っていなければなりません。どのようなスレッドがインスタンスを作成したかによって異なります。静的なミューテックスを使用すると、すべてのインスタンスが同じインスタンス(この場合はミューテックス)と同期します。これを実装するにはより良い方法があるかもしれませんが、これはあなたのユースケースでうまくいくと思います。 – tjg184

+0

OK ...意味があります。説明ありがとう。 – ryandlf

0

IndexWriterはすでにスレッドセーフです。

もしそうでなければ、すべてのインデックス操作を1つのスレッドで行うことを検討してください。その非常にJavaを使用して簡単にExecutorService

関連する問題