SearcherLifetimeManager입니다.


이 매니저클래스는 Searcher의 버전별 저장소라고 생각하시면 됩니다.

이 클래스가 없어도 Near Real Time Search를 사용 할 수 있는데요, 이 클래스가 필요한 이유를 아래의 블로그

http://www.searchworkings.org/blog/-/blogs/380754/maximized 에서는 이렇게 설명하고 있습니다.


무조건 새로운 버전의 IndexSearcher를 가지고, 실시간으로 인덱스의 변경 내용을 사용자에게 보여주는 것이

좋은 것은 아닙니다.


A라는 사람이 검색을 처음 시도하고, 1페이지에서 원하는 것을 찾지 못해 2페이지로 넘어가는 케이스에서, 다른 누군가에 의해 인덱스가 변경되어 새로운 IndexSearcher를 사용하여 페이징을 하게 되면 최악의 경우에는, A라는 사람은 똑같은 페이지를 다시 보게 되는 경우도 발생 할 수 있다는 것 입니다.


따라서, 페이징과 같은 연속된 검색 행동에 대해서는 처음 결과를 보여주었던 IndexSearcher를 그대로 사용하여 보여주는 것이 사용자에게 더 좋은 경험을 줄 수 있다는 것 입니다.


이럴때 사용하는것이 SearcherLifetimeManager입니다.


사용법은 간단합니다. 일단 IndexSearcher는 SearcherManager던 NRTManager던.. 다른 일반적인 방법으로 얻는다고 가정을 합니다.



SearcherLifetimeManager lifetimeManager = new SearcherLifetimeManager();

이 매니저 클래스는 몇가지 중요한 메서드를 제공합니다.


long recored(IndexSearcher searcher) 메서드는 현재 사용중인 searcher를 저장하고, 이 searcher의 버전 (여기서는 token이라고 부릅니다.)을 return 받습니다.


IndexSearcher(long token) 메서드는 위의 메서드로 저장된 token의 indexSearcher를 돌려받을 수 있습니다.


간단한 테스트케이스 소스입니다.


SearcherManager로부터 IndexSearcher를 받아냅니다. 처음에는 SearcherLifetimeManager에서 1 버전의 IndexSearcher를 요청하지만, record된 것이 없으므로 null이 return됩니다. 이후 record를 수행한 후 해당 버전의 IndexSearcher를 요청한 이후에는 정상적으로 검색을 수행 할 수 있습니다.

이렇게 return된 두개의 searcher는 아래의 조건을 만족합니다.



Assert.assertTrue(indexSearcher == newSearcher);


두번째 테스트케이스 코드입니다.




중간에 인덱스에 document를 하나 add하고 나서 새로 얻은 newSearcher를 record 한 후 이후 다시 lifetimeManager로부터 받아내어 검색을 수행하는 테스트 코드입니다. indexSearcher는 결과가 1, newSearcher는 결과가 2인 것을 확인 하실 수 있습니다.


또하나의 중요한 메서드가 있는데 바로 prune 메서드입니다.


void prune(Pruner p);


Pruner는 인터페이스인데, 이 인터페이스를 상속한 클래스에 의해서 record되어있던 indexSearcher들을 정리하는 역할을 합니다. 일단, 간단하게 이 인터페이스를 상속하여 구현한 클래스로 테스트한 코드입니다.



무조건 true를 return한게 되어있는데요, 그래서 record된 indexSearcher가 remove된 것을 보실 수 있습니다.

이 인터페이스를 구현한 기본 클래스가 하나 제공되는데요, PruneByAge 입니다.

생성자의 파라메터로 double 형을 받는데, 초단위로 생각하시면 됩니다.


테스트코드입니다.



이 메서드는 아래와 같이 설명이 되어있습니다.


/** Simple pruner that drops any searcher older by

   *  more than the specified seconds, than the newest

   *  searcher. */


가장 새로운 searcher와 비교해서 X초 이전의 searcher를 제거합니다. 위 테스트코드에서 firstSearcherToken으로 record된 indexSearcher만 삭제된 것을 보실 수 있습니다.


이 메서드는 새로운 searcher를 생성하는 스레드가 주기적으로 호출해주는 것이 좋다고 되어있습니다.


이 SearcherLifetimeManager를 활용하게 되면 굉장히 다양한 버전의 IndexSearcher가 생성되어 리소스에 큰 영향이 있지 않을까 우려가 있을 수도 있는데요, commiter의 설명으로는 리소스가 더 필요하긴 하겠지만 새롭게 생성되는 IndexSearcher들끼리는 점점 더 많은 sub-reader들을 공유 할 수 있기 때문에 우려 할 정도는 아닐 것이다 라고 이야기하네요.. 물론, 인덱스 파일의 굉장히 큰 변경 후 merge나 너무 잦은 index 파일의 변경으로 인한 reopen등의 조심해야 할 상황이 있기는 하겠습니다.


3.5부터 전반적으로 다루기 어려운 클래스들에 대해서 유틸성 클래스가 많이 제공되고 계속 변화되고 있는 것 같습니다.

사용하는 입장에서는 환영할 일이지만.. 개인적으로 이런 종류의 클래스를 필요에의해 만들면서 삽질하고 에러내고.. 하면서 배웠던 경험이 무척 소중했던지라... 앞으로 그런 기회마저 없어지는 것은 아닐지 좀 걱정이 되기도하네요. ^^


참고블로그 : http://www.searchworkings.org/blog/-/blogs/380754/maximized

테스트코드 : https://github.com/need4spd/aboutLucene



Posted by 용식