2009-11-19 5 views
6

저는 현재 대규모 데이터베이스에서 Lucene.NET 기반 검색을 구현하려고하고 있습니다. 본질적으로 관계형 데이터에 대한 검색을 시도해 왔습니다.Lucene.NET 인덱스에 관계형 데이터 저장

내가 검색하려고하는 데이터는 상위 수준에서 그룹화되며 각 항목은 1 ~ 3 개의 그룹에 속합니다. 그런 다음 그룹 조합 (EG : 각 항목은 그룹 A와 그룹 B 모두에 속함)에있는 모든 항목을 검색 할 수 있어야합니다.

각각의 그룹은 내가 검색하는 데이터의 ID와 설명을 가지고 있지만 설명은 서로의 하위 문자열 (예 : "Stuff"그룹과 "Other stuff"그룹) 일 수 있습니다. 내가 찾고있는 하위 문자열이있는 범주와 일치하지 않기를 바랍니다.

필자는이 필터링을 사용하지 않고 데이터를 가져 와서 ID를 필터링하는 것을 고려해 왔지만 성능상의 이유로 Lucene에서 반환 된 데이터에 페이지 매김을하려고했습니다. 또한 ID를 공백으로 구분하고 필드에서 텍스트 검색을하는 것으로 생각했지만 총 해킹처럼 보입니다 ...

이 검색을 가장 잘 처리하는 방법을 알고있는 사람이 있습니까? Lucene.NET? (다른 사람이 잘못된 도구를 사용한다고 말하기 전에 명확히하기 위해이 필터는 전체 텍스트 검색을 포함하는 더 큰 필터 집합의 하위 집합 일뿐입니다. 여전히 잘못된 도구를 사용하고 있다고 생각하면 마음에 듭니다. 무엇이 옳은지 들어라)

답변

5

나는 Lucene의 관계형 데이터를 저장하는 데 많은 어려움을 겪었지만, 당신이 가지고있는 것은 쉽게 고쳐야한다.

그룹 필드를 토큰으로 바꾸면 필드 값에서 하위 문자열을 검색 할 수 있습니다. 필드를 untokenized로 추가하면 예상대로 작동합니다.

는 다음의 짧은 코드를 확인하십시오 :

internal class Program { 
    private static void Main(string[] args) { 
     var directory = new RAMDirectory(); 
     var writer = new IndexWriter(directory, new StandardAnalyzer()); 
     AddDocument(writer, "group", "stuff", Field.Index.UN_TOKENIZED); 
     AddDocument(writer, "group", "other stuff", Field.Index.UN_TOKENIZED); 
     writer.Close(true); 

     var searcher = new IndexSearcher(directory); 
     Hits hits = searcher.Search(new TermQuery(new Term("group", "stuff"))); 

     for (int i = 0; i < hits.Length(); i++) { 
      Console.WriteLine(hits.Doc(i).GetField("group").StringValue()); 
     } 
    } 

    private static void AddDocument(IndexWriter writer, string name, string value, Field.Index index) { 
     var document = new Document(); 
     document.Add(new Field(name, value, Field.Store.YES, index)); 
     writer.AddDocument(document); 
    } 
} 

샘플은 untokenized있는 인덱스에 두 개의 문서를 추가는, 물건에 대한 검색을 수행하고 하나 개의 히트를 가져옵니다. 토큰 화 된 코드를 추가하도록 코드를 변경했다면 지금 보았던 것과 같이 두 번의 히트가 있습니다.

관계형 데이터에 Lucene을 사용할 때의 문제점은 와일드 카드 및 범위 검색이 항상 작동 할 것으로 예상된다는 것입니다. Lucene이 이러한 쿼리를 해결하는 방식 때문에 인덱스가 클 경우 실제로 그렇지 않습니다. 답장을

private static void Main(string[] args) { 
     var directory = new RAMDirectory(); 
     var writer = new IndexWriter(directory, new StandardAnalyzer()); 

     var documentA = new Document(); 
     documentA.Add(new Field("name", "A", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     documentA.Add(new Field("group", "stuff", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     documentA.Add(new Field("group", "other stuff", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     writer.AddDocument(documentA); 
     var documentB = new Document(); 
     documentB.Add(new Field("name", "B", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     documentB.Add(new Field("group", "stuff", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     writer.AddDocument(documentB); 
     var documentC = new Document(); 
     documentC.Add(new Field("name", "C", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     documentC.Add(new Field("group", "other stuff", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     writer.AddDocument(documentC); 

     writer.Close(true); 

     var query1 = new TermQuery(new Term("group", "stuff")); 
     SearchAndDisplay("First sample", directory, query1); 

     var query2 = new TermQuery(new Term("group", "other stuff")); 
     SearchAndDisplay("Second sample", directory, query2); 

     var query3 = new BooleanQuery(); 
     query3.Add(new TermQuery(new Term("group", "stuff")), BooleanClause.Occur.MUST); 
     query3.Add(new TermQuery(new Term("group", "other stuff")), BooleanClause.Occur.MUST); 
     SearchAndDisplay("Third sample", directory, query3); 
    } 

    private static void SearchAndDisplay(string title, Directory directory, Query query3) { 
     var searcher = new IndexSearcher(directory); 
     Hits hits = searcher.Search(query3); 
     Console.WriteLine(title); 
     for (int i = 0; i < hits.Length(); i++) { 
      Console.WriteLine(hits.Doc(i).GetField("name").StringValue()); 
     } 
    } 
+0

안녕 HakonB, 감사 :

또 다른 샘플

는 동작을 설명한다. 나는 몇 가지 다른 조회를 위해 untokenized를 사용했지만 문제는 하나의 항목이 "Stuff"및 "Other Stuff"에있을 수 있으며 하나 또는 둘 모두를 검색 할 때 발견되어야합니다. EG : 단지 물건 물건을 단지 다른 물건 검색 C {A, B} 다른 것들에 대한 검색 {A, C} 물건과 다른 물건 {에 대한 검색 물건과 다른 물건 B에서 A} – fyjham

+0

올바른 결과를 얻는 방법을 보여주는 또 다른 샘플을 추가했습니다. - 지금 이해하면 되겠습니다. – HakonB

+1

아, 고마워! 그게 정확히 내가 한 것 같아. 실제로 하나의 문서에 동일한 이름의 2 개의 필드를 추가 할 수는 없었습니다. 아직도 내가 생각하는 전형적인 관계형 데이터베이스와 너무 흡사하다.) – fyjham

관련 문제