0

コードベースを Lucene 3.6 から Lucene 4.1 に更新するだけで、アナライザーの文字を置き換えるために NormalizeCharMap を使用するテストが機能していないようです。

以下に、自己完結型のテスト ケースを作成しました。これは、実行したときの出力です。

--term=and--
--term=gold--
--term=platinum--
name:"platinum and gold"
Size1
name:"platinum & gold"
Size0

java.lang.AssertionError: 
Expected :1
Actual   :0
 <Click to see difference>
    at org.junit.Assert.fail(Assert.java:93)
    at org.junit.Assert.failNotEquals(Assert.java:647)
    at org.junit.Assert.assertEquals(Assert.java:128)
    at org.junit.Assert.assertEquals(Assert.java:472)
    at org.junit.Assert.assertEquals(Assert.java:456)
    at org.musicbrainz.search.analysis.Lucene41CharFilterTest.
    testAmpersandSearching(Lucene41CharFilterTest.java:89)

ご覧のとおり、charfilter は機能しているように見えます。これは、テキスト「platinum & gold」が 3 つの用語「platnum, and , gold」に変換されているためです。実際、検索は「プラチナとゴールド」では機能しますが、インデックスと検索の両方が同じアナライザーを使用しているにもかかわらず、元の「プラチナとゴールド」では機能しません

package org.musicbrainz.search.analysis;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.charfilter.MappingCharFilter;
import org.apache.lucene.analysis.charfilter.NormalizeCharMap;
import org.apache.lucene.analysis.core.LowerCaseFilter;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.Version;
import org.junit.Test;
import java.io.Reader;

import static org.junit.Assert.assertEquals;

public class Lucene41CharFilterTest
{
    class SimpleAnalyzer extends Analyzer {

        protected NormalizeCharMap charConvertMap;

        protected void setCharConvertMap() {

            NormalizeCharMap.Builder builder = new NormalizeCharMap.Builder();
            builder.add("&","and");
            charConvertMap = builder.build();
        }

        public SimpleAnalyzer() {
            setCharConvertMap();
        }

        @Override
        protected TokenStreamComponents createComponents(String fieldName, 
                                                         Reader reader) {
            Tokenizer source = new MusicbrainzTokenizer(Version.LUCENE_41,

                    new MappingCharFilter(charConvertMap, reader));
            TokenStream filter = new LowerCaseFilter(Version.LUCENE_41,source);
            return new TokenStreamComponents(source, filter);
        }
    }

    @Test
    public void testAmpersandSearching() throws Exception {

        Analyzer analyzer = new SimpleAnalyzer();
        RAMDirectory dir = new RAMDirectory();
        IndexWriterConfig writerConfig = new
            IndexWriterConfig(Version.LUCENE_41,analyzer);
        IndexWriter writer = new IndexWriter(dir, writerConfig);
        {
            Document doc = new Document();
            doc.add(new Field("name", "platinum & gold", Field.Store.YES,
                  Field.Index.ANALYZED));
            writer.addDocument(doc);
        }
        writer.close();

        IndexReader ir = DirectoryReader.open(dir);
        Fields fields = MultiFields.getFields(ir);
        Terms terms = fields.terms("name");
        TermsEnum termsEnum = terms.iterator(null);
        BytesRef text;
        while((text = termsEnum.next()) != null) {
            System.out.println("--term=" + text.utf8ToString()+"--");
        }
        ir.close();

        IndexSearcher searcher = new IndexSearcher(IndexReader.open(dir));
        {
            Query q = new QueryParser(Version.LUCENE_41, "name", analyzer)
                .parse("\"platinum and gold\"");
            System.out.println(q);
            TopDocs td = searcher.search(q, 10);
            System.out.println("Size"+td.scoreDocs.length);
            assertEquals(1, searcher.search(q, 10).totalHits);
        }

        searcher = new IndexSearcher(IndexReader.open(dir));
        {
            Query q = new QueryParser(Version.LUCENE_41, "name", analyzer)
                .parse("\"platinum & gold\"");
            System.out.println(q);
            TopDocs td = searcher.search(q, 10);
            System.out.println("Size"+td.scoreDocs.length);
            assertEquals(1, searcher.search(q, 10).totalHits);
        }
    }
}
4

2 に答える 2

0

よくわかりませんが、QueryParserは単なる分析以上のことをしていると思います。たとえば'と'は特別なキーワードです。あなたはちょうど面白いエッジケースにぶつかるかもしれません:)

4.1にはさらに多くのQueryParser実装があります...たとえば、http://lucene.apache.org/core/4_1_0/queryparser/org/apache/lucene/queryparser/flexible/standard/package-summary.htmlを参照してください。

于 2013-02-25T20:41:53.023 に答える
0

アナライザーが QueryParser で使用されている場合、新しい initReader() メソッドをオーバーライドして適用する必要があるという問題が見つかりました。フィルターを createComponents() でも構築する必要があるかどうかはわかりませんが、initReader に追加するだけでテストが機能します。

class SimpleAnalyzer extends Analyzer {

        protected NormalizeCharMap charConvertMap;

        protected void setCharConvertMap() {

            NormalizeCharMap.Builder builder = new NormalizeCharMap.Builder();
            builder.add("&","and");
            charConvertMap = builder.build();
        }

        public SimpleAnalyzer() {
            setCharConvertMap();
        }

        @Override
        protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
            Tokenizer source = new MusicbrainzTokenizer(Version.LUCENE_35,
                    reader);
            TokenStream filter = new LowerCaseFilter(Version.LUCENE_35,source);
            return new TokenStreamComponents(source, filter);
        }

        @Override
        protected Reader initReader(String fieldName,
                                    Reader reader)
        {
            return new MappingCharFilter(charConvertMap, reader);
        }
    }
于 2013-02-25T21:19:13.667 に答える