2016-10-11 14 views
2

Я пытаюсь сделать реляционный поиск с Lucene.NET 4.8 (на самом деле я скомпилировал его с помощью latest sources), следуя this post. I справка Lucene.Net, Lucene.Net.Analysis.Common, Lucene.Net.Grouping, Lucene.Net.Join и Lucene.Net.QueryParser.Lucene.NET: Как использовать BlockJoinQuery?

Проблема в следующем: результатов у меня нет. В моем примере ниже я рассматриваю blogparent, а comments - children. Я хочу найти блог, который содержит first и который имеет комментарий, содержащий like (который является одним из Id 1).

Как исправить этот пример кода?

static void BlockJoinQueryTest(string dbFolder) 
    { 
     var analyzer = new StandardAnalyzer(LuceneVersion.LUCENE_48); 
     var config = new IndexWriterConfig(LuceneVersion.LUCENE_48, analyzer); 
     config.SetOpenMode(IndexWriterConfig.OpenMode_e.CREATE_OR_APPEND); 

     var indexPathBlog = dbFolder + "\\blog_db"; 
     if (System.IO.Directory.Exists(indexPathBlog)) 
     { 
      System.IO.Directory.Delete(indexPathBlog, true); 
     } 
     System.IO.Directory.CreateDirectory(indexPathBlog); 
     var indexDirectoryBlog = FSDirectory.Open(new System.IO.DirectoryInfo(indexPathBlog)); 
     var indexWriterBlog = new IndexWriter(indexDirectoryBlog, config); 

     Document comment = new Document(); 
     comment.Add(new TextField("BlogId", "1", Field.Store.YES)); 
     comment.Add(new TextField("CommentContent", "I like your first blog!", Field.Store.YES)); 
     comment.Add(new TextField("Type", "comment", Field.Store.YES)); 
     comment.Add(new TextField("Note", "child", Field.Store.YES)); 
     indexWriterBlog.AddDocument(comment); 

     comment = new Document(); 
     comment.Add(new TextField("BlogId", "1", Field.Store.YES)); 
     comment.Add(new TextField("CommentContent", "Not that great.", Field.Store.YES)); 
     comment.Add(new TextField("Type", "comment", Field.Store.YES)); 
     comment.Add(new TextField("Note", "child", Field.Store.YES)); 
     indexWriterBlog.AddDocument(comment); 

     Document blog = new Document(); 
     blog.Add(new TextField("Id", "1", Field.Store.YES)); 
     blog.Add(new TextField("BlogContent", "Content of first blog", Field.Store.YES)); 
     blog.Add(new TextField("Type", "blog", Field.Store.YES)); 
     blog.Add(new TextField("Note", "parent", Field.Store.YES)); 
     indexWriterBlog.AddDocument(blog); 

     blog = new Document(); 
     blog.Add(new TextField("Id", "2", Field.Store.YES)); 
     blog.Add(new TextField("BlogContent", "This is the second blog!", Field.Store.YES)); 
     blog.Add(new TextField("Type", "blog", Field.Store.YES)); 
     blog.Add(new TextField("Note", "parent", Field.Store.YES)); 
     indexWriterBlog.AddDocument(blog); 

     indexWriterBlog.Commit(); 

     var searcher = new IndexSearcher(DirectoryReader.Open(indexDirectoryBlog)); 

     Console.WriteLine("Begin content enumeration:"); 
     for (int i = 0; i < searcher.IndexReader.MaxDoc; i++) 
     { 
      var doc = searcher.IndexReader.Document(i); 
      Console.WriteLine("Document " + i + ": " + doc.ToString()); 
     } 
     Console.WriteLine("End content enumeration."); 

     Filter blogs = new CachingWrapperFilter(
       new QueryWrapperFilter(
        new TermQuery(
        new Term("Type", "blog")))); 
     BooleanQuery commentQuery = new BooleanQuery(); 
     commentQuery.Add(new TermQuery(new Term("CommentContent", "like")), BooleanClause.Occur.MUST); 
     //commentQuery.Add(new TermQuery(new Term("BlogId", "1")), BooleanClause.Occur.MUST); 

     var commentJoinQuery = new ToParentBlockJoinQuery(
      commentQuery, 
      blogs, 
      ScoreMode.None); 

     BooleanQuery query = new BooleanQuery(); 
     query.Add(new TermQuery(new Term("BlogContent", "first")), BooleanClause.Occur.MUST); 
     query.Add(commentQuery, BooleanClause.Occur.MUST); 
     var c = new ToParentBlockJoinCollector(
      Sort.RELEVANCE, // sort 
      10,    // numHits 
      true,   // trackScores 
      false   // trackMaxScore 
      ); 
     searcher.Search(query, c); 
     int maxDocsPerGroup = 10; 
     var hits = c.GetTopGroups(
      commentJoinQuery, 
      Sort.INDEXORDER, 
      0, // offset 
      maxDocsPerGroup, // maxDocsPerGroup 
      0, // withinGroupOffset 
      true // fillSortFields 
     ); 
     if (hits != null) 
     { 
      Console.WriteLine("Found " + hits.TotalGroupCount + " groups:"); 
      for (int i = 0; i < hits.TotalGroupCount; i++) 
      { 
       var group = hits.Groups[i]; 
       Console.WriteLine("Group " + i + ": " + group.ToString()); 

       for (int j = 0; j < group.TotalHits && j < maxDocsPerGroup; j++) 
       { 
        Document doc = searcher.Doc(group.ScoreDocs[j].Doc); 
        Console.WriteLine("Hit " + i + ": " + doc.ToString()); 
       } 
      } 
     } 
     else 
     { 
      Console.WriteLine("No hits."); 
     } 

     Console.WriteLine("Done."); 
+0

Любое обновление к этому, вы ее решить? У меня есть аналогичная проблема ... – Ant

ответ

0

Вы не должны добавить Documents на одном дыхании, как IEnumerable, так что они «заблокированные»?

http://blog.mikemccandless.com/2012/01/searching-relational-content-with.html объясняет больше

EDIT:

я был пойти на делать это с помощью следующего кода, который также, кажется, не работает, был бы признателен, если кто может пролить свет?

 var analyzer = new StandardAnalyzer(LuceneVersion.LUCENE_48); 
     var config = new IndexWriterConfig(LuceneVersion.LUCENE_48, analyzer); 
     config.SetOpenMode(IndexWriterConfig.OpenMode_e.CREATE_OR_APPEND); 

     var indexPathBlog = "D:\\Test"; 
     if (System.IO.Directory.Exists(indexPathBlog)) 
     { 
      System.IO.Directory.Delete(indexPathBlog, true); 
     } 

     System.IO.Directory.CreateDirectory(indexPathBlog); 
     var indexDirectoryBlog = FSDirectory.Open(new System.IO.DirectoryInfo(indexPathBlog)); 
     var indexWriterBlog = new IndexWriter(indexDirectoryBlog, config); 

     var one = new List<Document>(); 
     var two = new List<Document>(); 

     var blogOne = new Document(); 
     blogOne.Add(new TextField("Id", "1", Field.Store.YES)); 
     blogOne.Add(new TextField("BlogContent", "Content of first blog", Field.Store.YES)); 
     blogOne.Add(new TextField("Type", "blog", Field.Store.YES)); 
     blogOne.Add(new TextField("Note", "parent", Field.Store.YES)); 
     one.Add(blogOne); 

     Document commentOne = new Document(); 
     commentOne.Add(new TextField("BlogId", "1", Field.Store.YES)); 
     commentOne.Add(new TextField("CommentContent", "I like your first blog!", Field.Store.YES)); 
     commentOne.Add(new TextField("Type", "comment", Field.Store.YES)); 
     commentOne.Add(new TextField("Note", "child", Field.Store.YES)); 
     one.Add(commentOne); 

     Document blogTwo = new Document(); 
     blogTwo.Add(new TextField("Id", "2", Field.Store.YES)); 
     blogTwo.Add(new TextField("BlogContent", "This is the second blog!", Field.Store.YES)); 
     blogTwo.Add(new TextField("Type", "blog", Field.Store.YES)); 
     blogTwo.Add(new TextField("Note", "parent", Field.Store.YES)); 
     two.Add(blogTwo); 

     var commentTwo = new Document(); 
     commentTwo.Add(new TextField("BlogId", "2", Field.Store.YES)); 
     commentTwo.Add(new TextField("CommentContent", "Not that great.", Field.Store.YES)); 
     commentTwo.Add(new TextField("Type", "comment", Field.Store.YES)); 
     commentTwo.Add(new TextField("Note", "child", Field.Store.YES)); 
     two.Add(commentTwo); 

     indexWriterBlog.AddDocuments(one); 
     indexWriterBlog.AddDocuments(two); 

     indexWriterBlog.Commit(); 

     var searcher = new IndexSearcher(DirectoryReader.Open(indexDirectoryBlog)); 

     Filter parentQuery = 
       new QueryWrapperFilter(
        new TermQuery(
        new Term("type", "blog"))); 

     BooleanQuery childQuery = new BooleanQuery(); 
     childQuery.Add(new TermQuery(new Term("CommentContent", "I like your first blog!")), BooleanClause.Occur.MUST); 

     var commentJoinQuery = new ToParentBlockJoinQuery(
      childQuery, 
      parentQuery, 
      ScoreMode.None); 

     BooleanQuery query = new BooleanQuery(); 
     //query.Add(new TermQuery(new Term("Type", "blog")), BooleanClause.Occur.MUST); 
     query.Add(commentJoinQuery, BooleanClause.Occur.MUST); 

     var c = new ToParentBlockJoinCollector(
      Sort.RELEVANCE, // sort 
      10,    // numHits 
      false,   // trackScores 
      false   // trackMaxScore 
      ); 

     searcher.Search(commentJoinQuery, c); 

     int maxDocsPerGroup = 10; 
     var hits = c.GetTopGroups(
      commentJoinQuery, 
      Sort.INDEXORDER, 
      0, // offset 
      maxDocsPerGroup, // maxDocsPerGroup 
      0, // withinGroupOffset 
      true // fillSortFields 
     ); 

     if (hits != null) 
     { 
      Console.WriteLine("Found " + hits.TotalGroupCount + " groups:"); 
      for (int i = 0; i < hits.TotalGroupCount; i++) 
      { 
       var group = hits.Groups[i]; 
       Console.WriteLine("Group " + i + ": " + group.ToString()); 

       for (int j = 0; j < group.TotalHits && j < maxDocsPerGroup; j++) 
       { 
        Document doc = searcher.Doc(group.ScoreDocs[j].Doc); 
        Console.WriteLine("Hit " + i + ": " + doc.ToString()); 
       } 
      } 
     } 
     else 
     { 
      Console.WriteLine("No hits."); 
     } 

     Console.WriteLine("Done."); 
+0

Взгляните на комментарии кода lucene.net. Порядок блоков неправильный, добавьте блог в последний раз, сначала комментарии. /// Этот запрос требует, чтобы вы указали /// дочерние и родительские документы как один блок, используя /// /// или /// API. В каждом блоке сначала должны отображаться дочерние документы//, заканчивающиеся родительским документом ///. –

0

Я также наткнулся на это и смог его исправить.

  • @ Неправильно указывать, что родительские документы ДОЛЖНЫ быть последними в блоке.

Но были две оставшиеся проблемы с кодом

  1. По какой-то причине - я прошу прощения за не будучи экспертом по Lucene - когда CommentCOntent является предложение ("Я люблю свой первый блог! "), и вы ищете его с помощью запроса Term, вы не получите никаких результатов. Я предполагаю, что это имеет какое-то отношение к анализу поля. Так что я сделал, чтобы заменить поля контента с «блог»

  2. Теперь IndexSercher, казалось, найти результат, но бросил ошибку как «System.InvalidOperationException:«parentFilter должен вернуть FixedBitSet, получил Lucene. Net.Search.QueryWrapperFilter + DocIdSetAnonymousInnerClassHelper» Просматривая тестируемых случаев Lucene.Net (Github), я увидел, что я должен был обернуть parentQuery в FixedBitSetCachingWrapperFilter: Filter parentQuery = new FixedBitSetCachingWrapperFilter( new QueryWrapperFilter( new TermQuery( new Term("Type", "blog"))));

полный код:

var analyzer = new StandardAnalyzer(LuceneVersion.LUCENE_48); 
      var config = new IndexWriterConfig(LuceneVersion.LUCENE_48, analyzer); 
      config.SetOpenMode(OpenMode.CREATE_OR_APPEND); 

      var indexPathBlog = Path.Combine(Environment.CurrentDirectory, "index"); 
      if (System.IO.Directory.Exists(indexPathBlog)) 
      { 
       System.IO.Directory.Delete(indexPathBlog, true); 
      } 

      System.IO.Directory.CreateDirectory(indexPathBlog); 
      var indexDirectoryBlog = FSDirectory.Open(new System.IO.DirectoryInfo(indexPathBlog)); 
      var indexWriterBlog = new IndexWriter(indexDirectoryBlog, config); 

      var one = new List<Document>(); 
      var two = new List<Document>(); 


      Document commentOne = new Document(); 
      commentOne.Add(new TextField("BlogId", "1", Field.Store.YES)); 
      commentOne.Add(new TextField("CommentContent", "blog", Field.Store.YES)); 
      commentOne.Add(new TextField("Type", "comment", Field.Store.YES)); 
      commentOne.Add(new TextField("Note", "child", Field.Store.YES)); 
      one.Add(commentOne); 

      var blogOne = new Document(); 
      blogOne.Add(new TextField("Id", "1", Field.Store.YES)); 
      blogOne.Add(new TextField("BlogContent", "Content of first blog!", Field.Store.YES)); 
      blogOne.Add(new TextField("Type", "blog", Field.Store.NO)); 
      blogOne.Add(new TextField("Note", "parent", Field.Store.YES)); 
      one.Add(blogOne); 

      var commentTwo = new Document(); 
      commentTwo.Add(new TextField("BlogId", "2", Field.Store.YES)); 
      commentTwo.Add(new TextField("CommentContent", "Not that great.", Field.Store.YES)); 
      commentTwo.Add(new TextField("Type", "comment", Field.Store.YES)); 
      commentTwo.Add(new TextField("Note", "child", Field.Store.YES)); 
      two.Add(commentTwo); 

      Document blogTwo = new Document(); 
      blogTwo.Add(new TextField("Id", "2", Field.Store.YES)); 
      blogTwo.Add(new TextField("BlogContent", "This is the second blog!", Field.Store.YES)); 
      blogTwo.Add(new TextField("Type", "blog", Field.Store.NO)); 
      blogTwo.Add(new TextField("Note", "parent", Field.Store.YES)); 
      two.Add(blogTwo); 

      indexWriterBlog.AddDocuments(one); 
      indexWriterBlog.AddDocuments(two); 

      indexWriterBlog.Commit(); 

      var searcher = new IndexSearcher(DirectoryReader.Open(indexDirectoryBlog)); 

      Filter parentQuery = 
       new FixedBitSetCachingWrapperFilter(
        new QueryWrapperFilter(
         new TermQuery(
          new Term("Type", "blog")))); 

      BooleanQuery childQuery = new BooleanQuery(); 
      childQuery.Add(new TermQuery(new Term("CommentContent", "blog")), Occur.MUST); 

      var commentJoinQuery = new ToParentBlockJoinQuery(
       childQuery, 
       parentQuery, 
       ScoreMode.None); 

      BooleanQuery query = new BooleanQuery(); 
      //query.Add(new TermQuery(new Term("Type", "blog")), BooleanClause.Occur.MUST); 
      query.Add(commentJoinQuery, Occur.MUST); 

      var c = new ToParentBlockJoinCollector(
       Sort.RELEVANCE, // sort 
       10,    // numHits 
       false,   // trackScores 
       false   // trackMaxScore 
      ); 

      searcher.Search(commentJoinQuery, c); 

      int maxDocsPerGroup = 10; 
      var hits = c.GetTopGroups(
       commentJoinQuery, 
       Sort.INDEXORDER, 
       0, // offset 
       maxDocsPerGroup, // maxDocsPerGroup 
       0, // withinGroupOffset 
       true // fillSortFields 
      ); 

      if (hits != null) 
      { 
       Console.WriteLine("Found " + hits.TotalGroupCount + " groups:"); 
       for (int i = 0; i < hits.TotalGroupCount; i++) 
       { 
        var group = hits.Groups[i]; 
        Console.WriteLine("Group " + i + ": " + group.ToString()); 

        for (int j = 0; j < group.TotalHits && j < maxDocsPerGroup; j++) 
        { 
         Document doc = searcher.Doc(group.ScoreDocs[j].Doc); 
         Console.WriteLine("Hit " + i + ": " + doc.ToString()); 
        } 
       } 
      } 
      else 
      { 
       Console.WriteLine("No hits."); 
      } 

      Console.WriteLine("Done."); 
      Console.ReadKey(); 

Обратите внимание, что я использовал следующие Pacakges в приложении консоли .NET Core:

<PackageReference Include="Lucene.Net" Version="4.8.0-beta00005" /> 
<PackageReference Include="Lucene.Net.Analysis.Common" Version="4.8.0-beta00005" /> 
<PackageReference Include="Lucene.Net.Join" Version="4.8.0-beta00005" />