2010-03-05 32 views
2

Je construis un index de recherche contenant des noms spéciaux - contenant! et ? et & et + et ... je dois marcher les recherches suivantes différentes:Lucene: Les caractères génériques sont absents de l'index

me & vous

-moi vous +

Mais quoi que je fasse (ai essayé avec QueryParser échapper avant indexation, échappaient manuellement, essayé différents indexeurs ...) - si je vérifie l'index de recherche avec Luke ils n'apparaissent pas (les points d'interrogation et @ -symbols et semblables se montrent)

La logique derrière est que je fais des recherches partielles pour une suggestion en direct (et les champs ne sont pas si gros), donc je le diviser en "m" et "moi" et "+" et "y" et "yo" et "vous", puis indexez-le (de cette façon, il est bien plus rapide qu'une recherche générique (et la taille de l'index n'est pas un gros problème).

Donc, ce dont j'ai besoin, c'est d'avoir aussi ces caractères génériques spéciaux à insérer dans l'index.

Ceci est mon code:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Text; 
using Lucene.Net.Analysis; 
using Lucene.Net.Util; 

namespace AnalyzerSpike 
{ 
    public class CustomAnalyzer : Analyzer 
    { 
     public override TokenStream TokenStream(string fieldName, TextReader reader) 
     { 
      return new ASCIIFoldingFilter(new LowerCaseFilter(new CustomCharTokenizer(reader))); 
     } 
    } 

    public class CustomCharTokenizer : CharTokenizer 
    { 
     public CustomCharTokenizer(TextReader input) : base(input) 
     { 

     } 

     public CustomCharTokenizer(AttributeSource source, TextReader input) : base(source, input) 
     { 
     } 

     public CustomCharTokenizer(AttributeFactory factory, TextReader input) : base(factory, input) 
     { 
     } 

     protected override bool IsTokenChar(char c) 
     { 
      return c != ' '; 
     } 
    } 
} 

Le code pour créer l'index:

private void InitIndex(string path, Analyzer analyzer) 
{ 
    var writer = new IndexWriter(path, analyzer, true); 

    //some multiline textbox that contains one item per line: 
    var all = new List<string>(txtAllAvailable.Text.Replace("\r","").Split('\n')); 

    foreach (var item in all) 
    { 
     writer.AddDocument(GetDocument(item)); 
    } 

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

private static Document GetDocument(string name) 
{ 
    var doc = new Document(); 

    doc.Add(new Field(
     "name", 
     DeNormalizeName(name), 
     Field.Store.YES, 
     Field.Index.ANALYZED)); 

    doc.Add(new Field(
       "raw_name", 
       name, 
       Field.Store.YES, 
       Field.Index.NOT_ANALYZED)); 

    return doc; 
} 

(code est avec Lucene.net dans la version 1.9.x (EDIT: désolé - était de 2,9. x) mais est compatible avec Lucene de Java)

Thx

+0

Êtes-vous sûr de vouloir dire 1.9. *? Vous mentionnez asciifoldingfilter qui ressemble à une variante 2.9. –

+0

Je devrais ajouter que l'essentiel de ce que vous avez décrit sonne bien, donc je soupçonne qu'il y a un problème dans le code que nous ne voyons pas dans votre analyseur. Est-ce que vous le dérivez d'une autre classe et ne remplacerez pas toutes les méthodes dont vous avez besoin, par exemple? –

+0

désolé - vous avez totalement raison - sa version 2.9.x - thx! J'ai mis à jour ma question et ai inclus tout le code approprié (le code de dénormaliser est juste une méthode faite sur commande pour additionner tous les espaces pour la recherche plus rapide – Eleasar

Répondre

0

finalement eu le temps de se pencher à nouveau. Et c'était une erreur stupide dans ma méthode denormalice qui a filtré les parties de caractère unique (comme c'était au début) et donc il a filtré le signe plus si entouré d'espaces: -/

Thx pour votre aide si Moleski!

private static string DeNormalizeName(string name) 
{ 
    string answer = string.Empty; 

    var wordsOnly = Regex.Replace(name, "[^\\w0-9 ]+", string.Empty); 
    var filterText = (name != wordsOnly) ? name + " " + wordsOnly : name; 

    foreach (var subName in filterText.Split(' ')) 
    { 
     if (subName.Length >= 1) 
     { 
      for (var j = 1; j <= subName.Length; j++) 
      { 
       answer += subName.Substring(0, j) + " "; 
      } 
     } 
    } 
    return answer.TrimEnd(); 
} 
+0

J'apprends comment faire ceci moi-même, pensez vous pourriez écrire le code pour votre Je ne suis pas sûr de ce que cela fait à ce moment-là Merci – Matt

+0

Je mets à jour ma réponse - mais ce n'est pas un code spécifique à Lucene - c'est juste pour mon cas particulier (et c'est juste un pic - Si vous voulez une recherche simple - alors oubliez ma méthode de dénormalisation, elle est juste utilisée dans mon cas particulier pour accélérer les suggestions en direct car une recherche générique est assez chère pour les petits mots - et je vouloir montrer des suggestions commençant par la première lettre ou la seconde. – Eleasar