2014-04-19 1 views
2

ASP.NET 프로젝트 검색에서 Lucene.net Standard Analyzer를 사용하고 있습니다. 그러나 그 검색은 C#, .NET 등의 키워드에 대한 결과를 반환하지 않습니다. 그러나 C 또는 NET (제거.)을 입력하면 작동합니다. (또한 Lucene을 사용하는) Stackoverflow에서 .NET을 입력하면 검색하는 동안 [.NET]으로 바뀌고 표준 분석기는 특수 문자 검색을 처리 할 수 ​​없다는 링크가 있고 White Space Analyzer는 기대 한 결과를 얻지 못하기 때문에 우리를 위해 일하십시오. SO가 검색을 관리하는 방법에 대해 도움을 줄 수 있습니까?Lucene SearchAnalyzer가 특수 문자 검색에 사용됩니다.

답변

2

내가 SO 더 밀접하게 여기 조금 무엇을하고 있는지의 특성을 것 "자바"또는 검색 할 때

I에 유래의 구현 세부 사항에 정말 관여 아니에요 동안, 당신은 같은 행동을 알게 될 것이다 표준 분석기에는 문제가 없을지라도 "최대 절전 모드"입니다. 그들은 "[java]"와 "[hibernate]"로 변형 될 것입니다. 그것은 단지 태그 검색을 나타냅니다. 그것은 "lucene"또는 "junit"을 검색 할 때 발생하지 않으므로 태그의 인기와 관련이 있습니다. 나는 태그 제목이 분석되지 않은 형태로 색인 될 것이라고 의심 할 것입니다.

흥미로운 예를 들어 "j ++"를 시도해보십시오. 이 막 다른 자바 구현은 SO에 태그를 사용하는 경우에만 8 개의 질문이 있으므로 자동 태그 검색을 실행하지 않습니다. "[j ++]"를 검색하면 해당 단어가 8 개 표시됩니다. "j ++"를 검색하면 해당 언어와 관련된 항목을 찾기가 힘들지 만 참조 번호 을 많이 찾을 수 있습니다.

온 워드, 당신의 문제를 해결하려면 다음

예, StandardAnalyzer이 모든 당신의 구두점을 제거 (부정확하게 말해서, 정확한 규칙에 대한 UAX-29 참조). 이에 대한 일반적인 접근 방식은 쿼리 할 때 동일한 분석기를 사용하는 것입니다. StandardAnalyzer을 사용하여 쿼리 및 인덱싱 된 문서를 분석하면 검색된 용어가 일치하므로 위에 언급 된 두 개의 쿼리 용어는 netc으로 줄어들며 결과를 얻어야합니다.

하지만 이제 의 고전적인 예가 StandardAnalyzer에 도달했습니다. 즉, c, c++c#은 모두 색인에서 정확하게 동일하게 나타납니다. 다른 두 개를 일치시키지 않고도 검색 할 수는 없습니다. 내 마음이 다룰 수있는 몇 가지 방법이 있습니다

:

  1. 목욕물과 함께 아기를 밖으로 던져 : 사용 WhitespaceAnalyzer 또는 일부 등, 모든 좋은, 멋진 일을 잃고 StandardAnalyzer 너를 도울거야. 루씬은 문장 부호를 좋아하지 않는, 그래서 그래, 당신은 그 문제가 몇 가지 알려진 측면이 :

  2. 그냥 그 몇 가지 작은 에지의 경우을 처리합니다. 다행히도 String.Replace입니다. "c", "cplusplus"및 "csharp"와 같이 좀 더 lucene-friendly 인 것으로 대체하십시오. 다시 말하지만 쿼리 및 인덱스 시간에 모두 완료되었는지 확인하십시오. 문제는입니다.이 작업은 분석기 외부에서 수행하기 때문에 변형은 필드의 저장된 버전에도 영향을 미치므로 사용자에게 결과를 표시하기 전에 변환을 취소해야합니다.

  3. 는 # 2와 동일한 작업을 수행하지만, 조금 애호가 : 그래서 # 2는 모든 권리를 작동 할 수 있습니다,하지만 당신은 이미에만 인덱스 버전에 영향을 루씬에 의해 소비에 대한 데이터를 변환 처리 이러한 분석기를 가지고 필드가 아닌 저장된 필드. 왜 사용하지 않습니까? 분석기에는 initReader이라는 전화가 있습니다. 여기서는 분석기 스택 앞에 CharFilter을 붙일 수 있습니다 (하단의 예제는 the Analysis package documentation 참조). 분석기를 통과하는 텍스트는 StandardTokenizer (구두점을 없애는 것 등) 이전에 CharFilter으로 변형됩니다. 특히 구두점을 제거하면됩니다. MappingCharFilter입니다.

당신이 사고 과정에 대한 자세한 설명에 관심이 있다면 당신은 StandardAnalyzer는하지만, 오히려 그것의 구현을 서브 클래스보다 분석기를 구현해야한다고되는 사고 (the discussion here을 볼 서브 클래스 수 없습니다 그곳에). 그래서, 우리는 우리가 절대적으로 얻을 수 있는지 확인하려면 가정 거래에서 StandardAnalyzer의 기능, 그냥 - 복사 붙여 넣기 소스 코드를, 그리고 initReaders 방법의 재정의 추가 모든 :

public class ExtraFancyStandardAnalyzer extends StopwordAnalyzerBase { 

    public static final int DEFAULT_MAX_TOKEN_LENGTH = 255; 

    private int maxTokenLength = DEFAULT_MAX_TOKEN_LENGTH; 

    public static final CharArraySet STOP_WORDS_SET = StopAnalyzer.ENGLISH_STOP_WORDS_SET; 

    public ExtraFancyStandardAnalyzer(Version matchVersion, 
      CharArraySet stopWords) { 
     super(matchVersion, stopWords); 
     buildMap(); 
    } 

    public ExtraFancyStandardAnalyzer(Version matchVersion) { 
     this(matchVersion, STOP_WORDS_SET); 
    } 

    public ExtraFancyStandardAnalyzer(Version matchVersion, Reader stopwords) 
      throws IOException { 
     this(matchVersion, loadStopwordSet(stopwords, matchVersion)); 
    } 

    public void setMaxTokenLength(int length) { 
     maxTokenLength = length; 
    } 

    public int getMaxTokenLength() { 
     return maxTokenLength; 
    } 


    // The following two methods, and a call to buildMap() in the ctor 
    // are the only things changed from StandardAnalyzer 

    private NormalizeCharMap map; 

    public void buildMap() { 
     NormalizeCharMap.Builder builder = new NormalizeCharMap.Builder(); 
     builder.add("c++", "cplusplus"); 
     builder.add("c#", "csharp"); 
     map = builder.build(); 
    } 

    @Override 
    protected Reader initReader(String fieldName, Reader reader) { 
     return new MappingCharFilter(map, reader); 
    } 

    @Override 
    protected TokenStreamComponents createComponents(final String fieldName, 
      final Reader reader) { 
     final StandardTokenizer src = new StandardTokenizer(matchVersion, 
       reader); 
     src.setMaxTokenLength(maxTokenLength); 
     TokenStream tok = new StandardFilter(matchVersion, src); 
     tok = new LowerCaseFilter(matchVersion, tok); 
     tok = new StopFilter(matchVersion, tok, stopwords); 
     return new TokenStreamComponents(src, tok) { 
      @Override 
      protected void setReader(final Reader reader) throws IOException { 
       src.setMaxTokenLength(ExtraFancyStandardAnalyzer.this.maxTokenLength); 
       super.setReader(reader); 
      } 
     }; 
    } 
} 

참고 :이 Java, Lucene 버전 4.7로 작성되고 테스트되었습니다. C# 구현은 너무 많이 다르면 안됩니다. StandardAnalyzer을 복사하고 MappingCharFilter (실제로는 버전 3.0.3에서 다루기가 더 간편한 머리카락)을 구축하고 initReader 메서드를 재정의하여 리더를 래핑하십시오.

+0

화려한 답변! – Vivek