2012-03-23 6 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

동기화 할 항목이 있어야합니다. 당신이 가지고 있던 방식은 "this"와 동기화 될 것이고, 이는 스레드가 인스턴스를 생성 한 것에 따라 다릅니다. 정적 뮤텍스를 사용하면 모든 인스턴스가 동일한 인스턴스 또는이 경우 뮤텍스와 동기화됩니다. 이 기능을 구현하는 데 더 좋은 방법이있을 수도 있지만 사용 사례와 함께 사용할 수 있다고 생각합니다. – tjg184

+0

좋습니다 ... 말이 맞습니다. 설명 해줘서 고마워. – ryandlf

0

IndexWriter가 이미 스레드 안전 가능한 사용 다른 스레드에서 동일한 인스턴스 만약 당신이 그렇게.

그렇지 않으면 단일 스레드에서 모든 인덱스 조작을 수행하십시오. 그 아주 쉽게 자바 ExecutorService을 사용하여 할 수 있습니다.