Lucene: в индексе отсутствуют подстановочные знаки

я создаю поисковый индекс, который содержит специальные имена - содержащие! и ? и & и + и ... Я должен выполнить следующие поиски по-разному:

мне вас

я + ты

Но что бы я ни делал (пытался с помощью queryparser экранировать перед индексированием, сбегал вручную, пробовал разные индексаторы ...) - если я проверяю индекс поиска с помощью Люка, они не отображаются (появляются вопросительные знаки, @ -символы и тому подобное. )

Логика заключается в том, что я выполняю частичный поиск действующего предложения (а поля не такие большие), поэтому я разделил его на «m», «me», «+», «y» и «yo» и « you ", а затем проиндексировать его (в этом случае это будет намного быстрее, чем поиск по запросу с подстановочными знаками (и размер индекса не является большой проблемой).

Так что мне нужно было бы также вставить эти специальные символы подстановки в индекс.

Это мой код:

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 != ' ';
        }
    }
}

Код для создания индекса:

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;
}

(Код с Lucene.net в версии 1.9.x (EDIT: извините - был 2.9.x), но совместим с Lucene из Java)

Спасибо


person Eleasar    schedule 05.03.2010    source источник
comment
Вы уверены, что имеете в виду 1.9. *? Вы упоминаете asciifoldingfilter, который звучит как вариант 2.9.   -  person Adrian Conlon    schedule 06.03.2010
comment
Я должен добавить, что суть того, что вы описали, звучит хорошо, поэтому я подозреваю, что есть проблема в коде, которую мы не видим в вашем анализаторе. Вы производите его из другого класса и, например, не переопределяете все методы, которые вам нужны?   -  person Adrian Conlon    schedule 06.03.2010
comment
извините - вы совершенно правы - его версия 2.9.x - спасибо! Я обновил свой вопрос и включил весь соответствующий код (код денормализации - это просто настраиваемый метод добавления всех пробелов для более быстрого поиска.   -  person Eleasar    schedule 07.03.2010


Ответы (1)


Наконец-то у меня появилось время еще раз взглянуть на это. И это была какая-то глупая ошибка в моем методе denormalice, который отфильтровал отдельные части символа (как это было в начале) и, таким образом, отфильтровал знак плюса, если он был окружен пробелами: - /

Спасибо за помощь, хотя 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();
}
person Eleasar    schedule 16.03.2010
comment
Я сам учусь делать это, как вы думаете, вы могли бы опубликовать код для своего метода денормализации? Я не понимаю, что это значит в данный момент. Спасибо. - person Matt; 30.03.2010
comment
Я обновляю свой ответ - но это не код, специфичный для Lucene - он предназначен только для моего особого случая (и это просто всплеск - поэтому не ожидайте идеального кода). Если вам нужен простой поиск - забудьте о моем методе денормализации. Он просто используется в моем частном случае для ускорения предложений в реальном времени, так как поиск с использованием подстановочных знаков для небольших слов довольно дорого обходится, и я хочу отображать предложения, начинающиеся с первой или второй буквы. - person Eleasar; 30.03.2010