5

3.6コードでは、次のようにインデックスに数値フィールドを追加していました。

public void addNumericField(IndexField field, Integer value) {
        addField(field, NumericUtils.intToPrefixCoded(value));
    }

ただし、ここでBytesRef引数を渡す必要があり、次の値で何をするのかが完全に不明確なので、代わりに(作業中)に変更しました

public void addNumericField(IndexField field, Integer value) {
        FieldType ft = new FieldType();
        ft.setStored(true);
        ft.setIndexed(true);
        ft.setNumericType(FieldType.NumericType.INT);
        doc.add(new IntField(field.getName(), value, ft));
    }

きちんと見えた

3.6では、queryparserをオーバーライドして、数値範囲検索で機能するようにすることも追加しました。

package org.musicbrainz.search.servlet;

import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.util.NumericUtils;
import org.musicbrainz.search.LuceneVersion;
import org.musicbrainz.search.index.LabelIndexField;
import org.musicbrainz.search.servlet.mmd1.LabelType;

public class LabelQueryParser extends MultiFieldQueryParser {

    public LabelQueryParser(java.lang.String[] strings, org.apache.lucene.analysis.Analyzer analyzer)
    {
        super(LuceneVersion.LUCENE_VERSION, strings, analyzer);
    }

     protected Query newTermQuery(Term term) {

        if(
                (term.field() == LabelIndexField.CODE.getName())
                ){
            try {
                int number = Integer.parseInt(term.text());
                TermQuery tq = new TermQuery(new Term(term.field(), NumericUtils.intToPrefixCoded(number)));
                return tq;
            }
            catch (NumberFormatException nfe) {
                //If not provided numeric argument just leave as is, 
                //won't give matches
                return super.newTermQuery(term);
            }
        } else {
            return super.newTermQuery(term);

        }
    }

    /**
     *
     * Convert Numeric Fields
     *
     * @param field
     * @param part1
     * @param part2
     * @param inclusive
     * @return
     */
    @Override
    public Query newRangeQuery(String field,
                               String part1,
                               String part2,
                               boolean inclusive) {

        if (
                (field.equals(LabelIndexField.CODE.getName()))
            )
        {
            part1 = NumericUtils.intToPrefixCoded(Integer.parseInt(part1));
            part2 = NumericUtils.intToPrefixCoded(Integer.parseInt(part2));
        }
        TermRangeQuery query = (TermRangeQuery)
                super.newRangeQuery(field, part1, part2,inclusive);
        return query;
    }

}

それで、私はもうそれを必要としないと考えてこれをすべて取り出しましたが、残念ながら、このIntFieldに対するクエリは現在機能していません。

さらに読むと、Intfieldsは範囲クエリにのみ使用されているようです。そのため、一致クエリを実行する方法や、NumericRangeQueryが私が使用している従来のクエリパーサーと互換性があるかどうかはわかりません。

それで、私は自分の数値をエンコードされた文字列として追加しようとすることに戻りました

public void addNumericField(IndexField field, Integer value) {

    FieldType fieldType = new FieldType();
    fieldType.setStored(true);
    fieldType.setIndexed(true);
    BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT);
    NumericUtils.intToPrefixCoded(value, 0, bytes);
    doc.add(new Field(field.getName(),bytes, fieldType));
}

しかし、実行時にエラーが発生します!

java.lang.IllegalArgumentException: Fields with BytesRef values cannot be indexed

ただし、フィールドにインデックスを付ける必要があるので、3.6のように数値フィールドにインデックスを付けて、検索できるようにするにはどうすればよいですか。

4

3 に答える 3

2

lucene 4.7 を使用してそれを行う方法について、注意してください。

インデックスを作成するときは、次のようにします。

document.add(new IntField("int_field", int_value, Field.Store.YES));

そして検索のために:

public class MyQueryParser extends QueryParser {

public MyQueryParser(Version matchVersion, String field, Analyzer anlayzer) {
    super(matchVersion, field, anlayzer);
}

@Override
protected Query getRangeQuery(String field, String part1, String part2, boolean startInclusive, boolean endInclusive) throws ParseException {
    if ("int_field".equals(field)) {
        return NumericRangeQuery.newIntRange(field, Integer.parseInt(part1), Integer.parseInt(part2), startInclusive, endInclusive);
    } else {
        return super.getRangeQuery(field, part1, part2, startInclusive, endInclusive);
    }
}

@Override
protected Query newTermQuery(Term term)
{
    if ("int_field".equals(term.field())) {
        try {
            int number = Integer.parseInt(term.text());
            BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT);
            NumericUtils.intToPrefixCoded(number, 0, bytes);
            TermQuery tq = new TermQuery(new Term(term.field(), bytes.utf8ToString()));
            return tq;
        } catch (NumberFormatException nfe) {
            //If not provided numeric argument just leave as is, won't give matches
            return super.newTermQuery(term);
        }
    } else {
        return super.newTermQuery(term);
    }
}

}

このようにすることで、次のようなクエリ

 int_field: 1
 int_field: [1 TO 5]

期待どおりに動作します。

于 2014-04-29T17:22:51.977 に答える
1

適切なフィールドを使用してください。たとえば、、IntFieldなどLongField

たとえば、http://lucene.apache.org/core/4_1_0/core/org/apache/lucene/document/IntField.htmlを参照してください。

これらのフィールドのクエリについては、Query を使用した Lucene LongField の完全一致検索を参照してください。

于 2013-02-25T20:07:02.487 に答える
0

だから、これが私が知らないことをするための最良の方法であるかどうかにかかわらず、私はこれを機能させました。

  1. 数値を文字列としてインデックスに追加する

    FieldType fieldType = new FieldType();
    fieldType.setStored(true);
    fieldType.setIndexed(true);
    BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT);
    NumericUtils.intToPrefixCoded(value, 0, bytes);
    doc.add(new Field(field.getName(),bytes.utf8ToString(), fieldType));
    
  2. QueryParser、equals() を使用してフィールド名をチェックする必要があります。以前は == を使用できました

    protected Query newTermQuery(Term term)
    {
    
       if (term.field().equals(LabelIndexField.CODE.getName()))
        {
            try
            {
    
                int number = Integer.parseInt(term.text());
                BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT);
                NumericUtils.intToPrefixCoded(number, 0, bytes);
                TermQuery tq = new TermQuery(new Term(term.field(), bytes.utf8ToString()));
                return tq;
            }
            catch (NumberFormatException nfe)
            {
                //If not provided numeric argument just leave as is, won't give matches
                return super.newTermQuery(term);
            }
        }
        else
        {
            return super.newTermQuery(term);
    
        }
    }
    
  3. また、newRangeQuery() の署名が変更され、追加のパラメーター endInclusive があります。

    public Query newRangeQuery(String field,
                               String part1,
                               String part2,
                               boolean startInclusive,
                               boolean endInclusive)
    {
        if (
                (field.equals(LabelIndexField.CODE.getName()))
                )
        {
            BytesRef bytes1 = new BytesRef(NumericUtils.BUF_SIZE_INT);
            BytesRef bytes2 = new BytesRef(NumericUtils.BUF_SIZE_INT);
            NumericUtils.intToPrefixCoded(Integer.parseInt(part1), 0, bytes1);
            NumericUtils.intToPrefixCoded(Integer.parseInt(part2), 0, bytes2);
            part1 = bytes1.utf8ToString();
            part2 = bytes2.utf8ToString();
        }
        TermRangeQuery query = (TermRangeQuery)
                super.newRangeQuery(field, part1, part2, startInclusive, endInclusive);
        return query;
    
    }
    
  4. 次のように、インデックスから元の整数値を取得できます。

    NumericUtils.prefixCodedToInt(new BytesRef(code))
    
于 2013-02-25T16:48:45.230 に答える