2016-05-19 5 views
2

In einer C# booleschen Abfrage Lucene Suche mit mehreren Feldern drei der Felder sind nicht in der Suche enthalten (SKU, VariantSkus und MPC), während die anderen Felder funktionieren gut.Lucene Feld nicht in ansonsten Arbeitssuche enthalten

Mit Luke kann ich sehen, dass die Werte im Index gespeichert sind. Bei der Suche in Luke bekomme ich die richtigen Ergebnisse, indem ich die Abfrage im Sucher (aus dem Debugger in Visual Studio) verwendet. Beispiel: Verwenden Sie die folgende Abfrage: (direkt aus dem Abfragewert genommen, während in Visual Studio Debuggen)

(+Mpc:B118^5) (+Sku:B118^5) (+Brand:B118) (+VariantSkus:B118^4) (+DisplayName:B118^3) (+DisplayName:B118*) (+DisplayName:B118~0.5) (+MisspelledNames:B118) (+Description:B118^0.4) 

Funktioniert nicht, während der Code ausgeführt wird (totalHits 0 auf dem Sucher), sondern gibt die erwarteten Ergebnis der Anpassung der Mpc an das richtige Produkt in Luke.

Ich bin ehrlich gesagt ziemlich verwirrt, warum die gleiche Abfrage nicht im C# -Code funktioniert. Jede Hilfe oder Vorschläge wären willkommen.

Erstellung des Index:

 public static String CreateLuceneIndex(string basePath, HttpContext context) 
    { 
     var stopwatch = new Stopwatch(); 

     /* get the absolute path to the directory where the indexes will be created (and if it doesn't exist, create it) */ 
     var dirPath = context.Server.MapPath(basePath); 
     if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath); 
     var di = new DirectoryInfo(dirPath); 
     var directory = FSDirectory.Open(di); 

     stopwatch.Start(); 

     /* Select the standard Lucene analyser */ 
     var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29); 
     var count = 0; 
     var catalog = ProductCatalog.All().First(); 

     /* Open the index writer using the selected analyser */ 
     using (var writer = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED)) 
     using(var mediaRepository = new ProductMediaRepository()) 
     { 
      var urlService = ObjectFactory.Instance.Resolve<IUrlService>(); 

      // Get all the visible products from uCommerce we wish to index 
      foreach (var product in Product.Find(p => p.DisplayOnSite && p.ParentProduct == null)) 
      { 
       var url = urlService.GetUrl(catalog, product); 

       var doc = new Document(); 
       doc.Add(new Field("id", product.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.YES)); 
       doc.Add(new Field("Url", url ?? String.Empty, Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.YES)); 
       doc.Add(new Field("Src", ImageService.GetProductMainImage(mediaRepository, product).Src ?? String.Empty 
        , Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.YES)); 
       doc.Add(new Field("Sku", product.Sku ?? String.Empty, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES)); 

       var varianSkus = String.Join(" ", product.Variants.Select(variant => variant.VariantSku)); 
       doc.Add(new Field("VariantSkus", varianSkus, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES)); 

       doc.Add(new Field("DisplayName", product.DisplayName() ?? product.Name ?? String.Empty, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES)); 
       var brands = String.Join(" ", product.Variants.Select(variant => variant.GetPropertyValue<String>("Brand")).Where(w => !String.IsNullOrWhiteSpace(w))); 
       doc.Add(new Field("Brand", brands ?? String.Empty, Field.Store.NO, Field.Index.ANALYZED, Field.TermVector.YES)); 

       doc.Add(new Field("MisspelledNames", product.GetPropertyValue<String>("MisspelledNames") ?? String.Empty, 
        Field.Store.NO, Field.Index.ANALYZED, Field.TermVector.YES)); 

       doc.Add(new Field("Description", product.ShortDescription()?.StripHtml() ?? String.Empty, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES)); 

       doc.Add(new Field("Mpc", product.GetPropertyValue<String>("MPC") ?? String.Empty, Field.Store.NO, Field.Index.NOT_ANALYZED, Field.TermVector.YES)); 

       writer.AddDocument(doc); 
       count++; 
      } 

      writer.Optimize(); 
      writer.Close(); 
     } 

     stopwatch.Stop(); 
     return $"Indexed {count} products in {stopwatch.Elapsed}.\n\n"; 

Searching:

 public static ListItemsDtoModel ProductSearch(String searchTerm, String indexDirPath, Int32 maxResults = Int32.MaxValue) 
    { 
     searchTerm = searchTerm.Trim().ToLowerInvariant(); 
     var searchWords = ParseSearchWords(searchTerm); 

     indexDirPath = HttpContext.Current.Server.MapPath(indexDirPath); 
     var di = new DirectoryInfo(indexDirPath); 

     using (var directory = FSDirectory.Open(di)) 
     using (var searcher = new IndexSearcher(IndexReader.Open(directory, true))) 
     { 
       var query = new BooleanQuery(); 

       query.Add(new BooleanClause(AddTermClauseGroup("Mpc", searchWords, 5), BooleanClause.Occur.SHOULD)); 
       query.Add(new BooleanClause(AddTermClauseGroup("Sku", searchWords, 5), BooleanClause.Occur.SHOULD)); 
       query.Add(new BooleanClause(AddTermClauseGroup("Brand", searchWords), BooleanClause.Occur.SHOULD)); 
       query.Add(new BooleanClause(AddTermClauseGroup("VariantSkus", searchWords, 4), BooleanClause.Occur.SHOULD)); 
       query.Add(new BooleanClause(AddTermClauseGroup("DisplayName", searchWords, 3), BooleanClause.Occur.SHOULD)); 
       query.Add(new BooleanClause(AddWildcardClauseGroup("DisplayName", searchWords), BooleanClause.Occur.SHOULD)); 
       query.Add(new BooleanClause(AddFuzzyTermClauseGroup("DisplayName", searchWords), BooleanClause.Occur.SHOULD)); 
       query.Add(new BooleanClause(AddTermClauseGroup("MisspelledNames", searchWords), BooleanClause.Occur.SHOULD)); 
       query.Add(new BooleanClause(AddTermClauseGroup("Description", searchWords, 0.4f), BooleanClause.Occur.SHOULD)); 

       var searchResults = searcher.Search(query, maxResults); 

       return AsListItemsDtoModel(searchResults.ScoreDocs.Select(sd => 
       { 
        var document = searcher.Doc(sd.doc); 
        return new ImageLinkDtoModel 
        { 
         Url = document.Get("Url"), 
         Text = document.Get("DisplayName"), 
         Alt = document.Get("DisplayName"), 
         Src = document.Get("Src"), 
        }; 
       }).ToList()); 
     } 
    } 
    private static String[] ParseSearchWords(string searchTerm) 
    { 
     return searchTerm.Split(' ', '-') 
      .Where(w => !String.IsNullOrWhiteSpace(w)) 
      .Select(QueryParser.Escape) 
      .ToArray(); 
    } 


    private static BooleanQuery AddTermClauseGroup(String field, IEnumerable<String> searchTerms, float boost = 1f) 
    { 
     var boostStr = Math.Abs(boost-1f) > 0.001 ? "^" + boost.ToString(CultureInfo.InvariantCulture) : String.Empty; 

     return AddClauseGroup(searchTerms, word => new TermQuery(new Term(field, word + boostStr))); 
    } 

    private static BooleanQuery AddFuzzyTermClauseGroup(String field, IEnumerable<String> searchTerms) 
    { 
     return AddClauseGroup(searchTerms, word => new FuzzyQuery(new Term(field, word), 0.5f)); 
    } 

    private static BooleanQuery AddWildcardClauseGroup(String field, IEnumerable<String> searchTerms) 
    { 
     return AddClauseGroup(searchTerms, word => new WildcardQuery(new Term(field, word + "*"))); 
    } 

    private static BooleanQuery AddClauseGroup(IEnumerable<String> searchTerms, Func<String, Query> createSubClause) 
    { 
     var query = new BooleanQuery(); 

     foreach (var searchTerm in searchTerms) 
     { 
      query.Add(new BooleanClause(createSubClause(searchTerm), BooleanClause.Occur.MUST)); 
     } 
     return query; 
    } 

Antwort

0

Das Problem in der Art und Weise ist, dass Sie die Anwendung steigert:

return AddClauseGroup(searchTerms, word => new TermQuery(new Term(field, word + boostStr))); 

Sie können den Auftrieb nicht integrieren in den Begriff selbst auf diese Weise. Da hier kein QueryParser im Spiel ist, wird die QueryParser-Syntax wie "term^4" nicht funktionieren. Es wird nur nach der Zeichenfolge "term^4" mit dem Standard-Boost von 1.0 gesucht. Ein Termquery mit einem Schub würde wie folgt aussehen:

Query query = new TermQuery(new Term(field, word)); 
query.Boost = boost; 
+0

ich den Termquery-Code geändert: private static BooleanQuery AddTermClauseGroup (String Feld, IEnumerable search, float boostValue = 1f) { return AddClauseGroup (search, Wort => { var Termquery = new Termquery (neue Bezeichnung (Feld, Wort)); if (Math.Abs ​​(boostValue - 1f)> 0.001) termQuery.SetBoost (boostValue); return Termquery; }); } , und es löste das Problem. –