Оператор NOT не работает в запросе lucene

Я использую Lucene версии 3.0.3.0, но некоторые выражения, которые я ищу, не работают должным образом. например, если я ищу "!Fiesta ИЛИ Astra" в поле "Модель", возвращается только "vauxhallAstra" и не возвращается "fordFocus". мой код ниже:

var fordFiesta = new Document();

        fordFiesta.Add(new Field("Id", "1", Field.Store.YES, Field.Index.NOT_ANALYZED));

        fordFiesta.Add(new Field("Make", "Ford", Field.Store.YES, Field.Index.ANALYZED));

        fordFiesta.Add(new Field("Model", "Fiesta", Field.Store.YES, Field.Index.ANALYZED));



        var fordFocus = new Document();

        fordFocus.Add(new Field("Id", "2", Field.Store.YES, Field.Index.NOT_ANALYZED));

        fordFocus.Add(new Field("Make", "Ford", Field.Store.YES, Field.Index.ANALYZED));

        fordFocus.Add(new Field("Model", "Focus", Field.Store.YES, Field.Index.ANALYZED));



        var vauxhallAstra = new Document();

        vauxhallAstra.Add(new Field("Id", "3", Field.Store.YES, Field.Index.NOT_ANALYZED));

        vauxhallAstra.Add(new Field("Make", "Vauxhall", Field.Store.YES, Field.Index.ANALYZED));

        vauxhallAstra.Add(new Field("Model", "Astra", Field.Store.YES, Field.Index.ANALYZED));







        Directory directory = FSDirectory.Open(new DirectoryInfo(Environment.CurrentDirectory + "\\LuceneIndex"));

        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);





        var writer = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);

        writer.AddDocument(fordFiesta);

        writer.AddDocument(fordFocus);

        writer.AddDocument(vauxhallAstra);


        writer.Optimize();                       

        writer.Close();

        IndexReader indexReader = IndexReader.Open(directory, true);
        Searcher indexSearch = new IndexSearcher(indexReader);

        var queryParser = new QueryParser(Version.LUCENE_30, "Model", analyzer);
        var query = queryParser.Parse("!Fiesta OR Astra");

        Console.WriteLine("Searching for: " + query.ToString());
        TopDocs resultDocs = indexSearch.Search(query, 200);            
        Console.WriteLine("Results Found: " + resultDocs.MaxScore);

        var hits = resultDocs.ScoreDocs;
        foreach (var hit in hits)
        {
            var documentFromSearcher = indexSearch.Doc(hit.Doc);
            Console.WriteLine(documentFromSearcher.Get("Make") + " " + documentFromSearcher.Get("Model"));
        }

        indexSearch.Close();
        directory.Close();

        Console.ReadKey();

1 ответ

Решение

!Fiesta OR Astra не означает, что вы думаете, что это значит. !Fiesta часть не означает "получить все, кроме Fiesta", как вы могли ожидать, а скорее "запретить Fiesta". NOT термин в запросе Lucene только отфильтровывает результаты, он ничего не находит.

Единственный определенный вами запрос, который на самом деле будет получать результаты: Astra, Таким образом, будет найдено все, что содержит Astra, а затем Fiesta будет отфильтровано.

Чтобы выполнить запрос, который, я полагаю, вы ожидаете, вам понадобится что-то вроде:

Astra OR (*:* !Fiesta)

*:* как MatchAllDocsQuery, Поскольку для выполнения запроса такого типа необходимо сопоставить все документы, можно ожидать, что он будет работать плохо.


Вот почему я действительно не люблю синтаксис AND/OR/NOT для Lucene. +/- намного яснее, мощнее и не содержит таких странных ошибок, как эта.

Эта превосходная статья на эту тему проясняет, почему вы должны думать с точки зрения MUST/MUST_NOT/SHOULD, а не традиционная логическая логика.

Другие вопросы по тегам