2016-03-09 2 views
1

Je suis en train de rassembler une preuve de concept pour la recherche Fulltext dans notre application en utilisant Lucene.NET. Certaines requêtes fonctionnent correctement, d'autres semblent renvoyer des résultats qui ne correspondent pas à ceux renvoyés par l'outil Luke. Plus problématiquement, cette requête:Exception d'exécution Lucene.NET cohérente sur certaines requêtes

(Description:tasty) (Gtin:00018389732061) 

donne toujours cette exception:

Une exception non gérée du type 'System.IndexOutOfRangeException' a eu lieu en Lucene.Net.dll à Lucene.Net.Search.TermScorer .Score() dans d: \ Lucene.Net \ FullRepo \ tronc \ src \ core \ Search \ TermScorer.cs: ligne 136 à Lucene.Net.Search.BooleanScorer.BooleanScorerCollector.Collect (Int32 doc) dans d: \ Lucene.Net \ FullRepo \ tronc \ src \ core \ Search \ BooleanScorer.cs: lin e 88 à Lucene.Net.Search.TermScorer.Score (Collecteur c, Int32 fin, Int32 firstDocID) dans d: \ Lucene.Net \ FullRepo \ trunk \ src \ core \ Search \ TermScorer.cs: ligne 80
à Lucene.Net.Search.BooleanScorer.Score (Collecteur collecteur, Int32 max, Int32 firstDocID) dans d: \ Lucene.Net \ FullRepo \ trunk \ src \ core \ Search \ BooleanScorer.cs: ligne 323 à Lucene .Net.Search.BooleanScorer.Score (collecteur collecteur) dans d: \ Lucene.Net \ FullRepo \ trunk \ src \ core \ Search \ BooleanScorer.cs: ligne 389 à Lucene.Net.Search.IndexSearcher.Search (poids poids, filtre , collecteur collecteur) dans d: \ Lucene.Net \ FullRepo \ trunk \ src \ core \ Search \ IndexSearcher.cs: ligne 228 à Lucene.Net.Search.IndexSearcher.Search (poids, filtre filtre, Int32 nDocs) dans d: \ Lucene.Net \ FullRepo \ trunk \ src \ core \ Search \ IndexSearcher.cs: ligne 188 à Lucene.Net.Search.Searcher.Search (Requête de requête, Filtre de filtre, Int32 n) dans d: \ Lucene.Net \ FullRepo \ tronc \ src \ core \ Search \ Searcher.cs: ligne 108 à Lucene.Net. Search.Searcher.Search (requête de requête, Int32 n) dans d: \ Lucene.Net \ FullRepo \ tronc \ src \ core \ Search \ Searcher.cs: ligne 118
à ...

Si J'utilise cette requête à la place:

(Description:tasty) (Gtin:000) 

Je reçois des résultats. Quelle est la cause de l'exception dans la requête du haut? FWIW, voici l'extrait de code correspondant:

protected virtual IList<Document> GetDocuments(BooleanQuery query, DirectoryInfo indexLocation, string defaultField) 
     { 
      var docs = new List<Document>(); 

      using (var dir = new MMapDirectory(indexLocation)) 
      { 
       using (var searcher = new IndexSearcher(dir)) 
       {       
        var queryParser = new QueryParser(Constants.LuceneVersion, defaultField, new StandardAnalyzer(Constants.LuceneVersion)); 
        TopDocs result = searcher.Search(query, Constants.MaxHits); 

        if (result == null) return docs; 

        foreach (var scoredoc in result.ScoreDocs.OrderByDescending(d => d.Score)) 
        { 
         docs.Add(searcher.Doc(scoredoc.Doc)); 
        } 
        return docs; 
       } 
      } 
     } 

Sur la base des commentaires ci-dessous, voici mon code actuel non modifié qui ne fonctionne toujours pas.

protected virtual IList<Document> GetDocuments(BooleanQuery query, DirectoryInfo indexLocation, string defaultField) 
     { 
      var docs = new List<Document>(); 

      using (var dir = new MMapDirectory(indexLocation)) 
      { 
       using (var searcher = new IndexSearcher(dir)) 
       { 
        using (var analyzer = new StandardAnalyzer(Constants.LuceneVersion)) 
        { 
         var queryParser = new QueryParser(Constants.LuceneVersion, defaultField, analyzer); 
         var collector = TopScoreDocCollector.Create(Constants.MaxHits, true); 
         var parsed = queryParser.Parse(query.ToString()); 
         searcher.Search(parsed, collector); 

         var docsresult = new List<string>(); 
         var matches = collector.TopDocs().ScoreDocs; 
         foreach (var scoredoc in matches.OrderByDescending(d => d.Score)) 
         { 
          docs.Add(searcher.Doc(scoredoc.Doc)); 
         } 
         return docs; 
        } 
       } 
      } 
     } 
+0

En outre, cette requête: + (Description: savoureux) + Gtin: 000 * ne renvoie aucun résultat sur mon impl implant Lucene.NET, alors que Luke (correctement) renvoie 11 documents correspondants. – HelluvaEngineer

+0

Est-ce que "Gtin" est indexé comme une chaîne ou un champ numérique? – AndyPook

+1

Luke renverra souvent des résultats "différents" car l'analyseur est souvent différent de la façon dont les champs ont été indexés – AndyPook

Répondre

1

Pas strictement une réponse car il "fonctionne sur ma machine". Poster comme réponse pour que je puisse partager le code de test unitaire qui "fonctionne". Espérons que le PO peut montrer ce qui est différent avec leur version.

Cette version suppose que le champ "Gtin" est un champ chaîne et est pas analysé (car il semble être un code).

[TestClass] 
public class UnitTest4 
{ 
    [TestMethod] 
    public void TestLucene() 
    { 
     var writer = CreateIndex(); 
     Add(writer, "tasty", "00018389732061"); 
     writer.Flush(true, true, true); 

     var searcher = new IndexSearcher(writer.GetReader()); 
     Test(searcher, "(Description:tasty) (Gtin:00018389732061)"); 
     Test(searcher, "Description:tasty Gtin:00018389732061"); 
     Test(searcher, "+Description:tasty +Gtin:00018389732061"); 
     Test(searcher, "+Description:tasty +Gtin:000*"); 

     writer.Dispose(); 
    } 

    private void Test(IndexSearcher searcher, string query) 
    { 
     var result = Search(searcher, query); 
     Console.WriteLine(string.Join(", ", result)); 
     Assert.AreEqual(1, result.Count); 
     Assert.AreEqual("00018389732061", result[0]); 
    } 

    private List<string> Search(IndexSearcher searcher, string expr) 
    { 
     using (var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30)) 
     { 
      var queryParser = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, "Description", analyzer); 
      var collector = TopScoreDocCollector.Create(1000, true); 
      var query = queryParser.Parse(expr); 
      searcher.Search(query, collector); 

      var result = new List<string>(); 
      var matches = collector.TopDocs().ScoreDocs; 
      foreach (var item in matches) 
      { 
       var id = item.Doc; 
       var doc = searcher.Doc(id); 
       result.Add(doc.GetField("Gtin").StringValue); 
      } 
      return result; 
     } 
    } 

    IndexWriter CreateIndex() 
    { 
     var directory = new RAMDirectory(); 

     var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30); 
     var writer = new IndexWriter(directory, analyzer, new IndexWriter.MaxFieldLength(1000)); 

     return writer; 
    } 
    void Add(IndexWriter writer, string desc, string id) 
    { 
     var document = new Document(); 
     document.Add(new Field("Description", desc, Field.Store.YES, Field.Index.ANALYZED)); 
     document.Add(new Field("Gtin", id, Field.Store.YES, Field.Index.NOT_ANALYZED)); 

     writer.AddDocument(document); 
    } 
} 
+0

J'ai apparemment flairé la chose GTIN. Tu as raison. C'est un champ de code. N'a pas réalisé que le paramètre d'analyse doit être défini sur false. Va essayer ça maintenant ... – HelluvaEngineer

+0

OK, j'ai essayé une légère variation de la tienne. J'ai converti GTIN pour ne pas être analysé. Aussi, je convertis la requête en texte. Pas de joie. Même erreur bouillonnante dans la pile. Notez que j'ai un index physique, pas en-mem donc le code est un peu différent ... ack, le code est trop long, je vais essayer d'éditer mon post original – HelluvaEngineer

+0

tout champ qui contient un code/clé/type d'id chose devrait être NOT_ANALYZED. Le type de répertoire utilisé dans le code de base ne changera rien au comportement. Cependant, dans lucene.net je ne pense pas que MMAPDirectory ait réellement des avantages (il pourrait même y avoir des bugs) pourriez-vous essayer avec un simple FSDirectory. Windows fait un très bon travail de mise en cache du contenu des fichiers. Comme les fichiers de segment sont écrits une fois puis en lecture seule, vous obtenez quand même de très bonnes caractéristiques de performance. – AndyPook