0

I'm trying to perform a search for an integer value. I have annotated the param with @Field like this:

@Field(name = "confirmedCount", index = UN_TOKENIZED, store = Store.YES)
public int getConfirmedCount() {
   return stuff.size();
}

I then perform a range search with luke:

confirmedCount:[5 TO 100]

the result that I get back is empty. I then try:

confirmedCount:[1 TO 2]

The result is:

name confirmedCount
b    1
a    1
d    19
c    2

So my question is: Why do I get this response and how do I solve it? I use hibernate search 3.0.1.GA

jakob
  • 5,979
  • 7
  • 64
  • 103

3 Answers3

3

Ok I guess the answer to my question is RTFM! The documentation clearly states:

Numbers are converted into their string representation. Note that numbers cannot be compared by Lucene (ie used in ranged queries) out of the box: they have to be padded

So we need to implement a class bridge:

public class PaddedIntegerBridge implements StringBridge {

    private int PADDING = 5;

    public String objectToString(Object object) {
        String rawInteger = ( (Integer) object ).toString();
        if (rawInteger.length() > PADDING)
            throw new IllegalArgumentException( "Try to pad on a number too big" );
        StringBuilder paddedInteger = new StringBuilder( );
        for ( int padIndex = rawInteger.length() ; padIndex < PADDING ; padIndex++ ) {
            paddedInteger.append('0');
        }
        return paddedInteger.append( rawInteger ).toString();
    }
}

Then we need to annotate the field so that it get indexed:

@Field(name = "confirmedCount", index = UN_TOKENIZED, store = Store.YES, bridge = @FieldBridge(impl = PaddedIntegerBridge.class))
    public int getConfirmedCount() {
        return stuff.size();
    }

Then in my searches I just need to make use of this bridge when creating a query and voila it works =)

Some testing with Luke:

confirmedCount:[00005 TO 00100]

name confirmedCount
g    00006
d    00019
jakob
  • 5,979
  • 7
  • 64
  • 103
3

I couldn't find the documentation for 3.0.1 GA, but newer versions of Hibernate Search have a NumericField annotation.

jpountz
  • 9,904
  • 1
  • 31
  • 39
  • That's what I would have used but NumericField wasn't introduced until 3.3 http://docs.jboss.org/hibernate/search/3.2/api/org/hibernate/search/annotations/ http://docs.jboss.org/hibernate/search/3.3/api/org/hibernate/search/annotations/ =) – jakob Mar 21 '12 at 09:59
  • Then you might be interested in upgrading since NumericField provides better performance for range queries http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/api/all/org/apache/lucene/search/NumericRangeQuery.html – jpountz Mar 21 '12 at 10:03
0

If you have string type field but you want to sort as number wise and apply rang query on that. you must have convert string field to number field but here without converting field you can implement rang query on field and apply sorting like as number.

Add or create custom @FieldBridge on field.

@Field(index=Index.YES,analyze=Analyze.NO,store=Store.YES) @FieldBridge(impl=StringToNumberBridge.class)

private String currentCtc;

Suppose you want to search currentCtc field as number but it's string field. You can implement Rang Query on currentCtc field.

public class StringToNumberBridge implements TwoWayStringBridge {

    Logger logger=Logger.getLogger(StringToNumberBridge.class);
    public static String PADDING_PROPERTY = "padding";
    private int padding = 7; //default

    public String objectToString(Object object) {

        try {
            if(object!=null) 
            {
                String rawInteger = ((String) object).toString();
                String decimalPoint="";

                if(rawInteger.matches("\\d*\\.\\d+")) 
                {
                    decimalPoint=rawInteger.substring(rawInteger.indexOf("."));
                    rawInteger=rawInteger.substring(0,rawInteger.indexOf("."));
                    System.out.println(decimalPoint);
                    System.out.println(rawInteger);
                }
                if (rawInteger.length() > padding)
                    throw new IllegalArgumentException("Try to pad on a number too big");

                StringBuilder paddedInteger = new StringBuilder();
                for (int padIndex = rawInteger.length(); padIndex < padding; padIndex++) 
                {
                    paddedInteger.append('0');
                }
                return paddedInteger.append(rawInteger).append(decimalPoint).toString();
            }
            else {
                return "";
            }
            //return object.toString();
        } 
        catch (Exception e) {
            logger.error("NumberFormateException:::::::::::"+e);
            return null;
        }
    }

    public Object stringToObject(String stringValue) {
        return Double.valueOf(stringValue);
    }
}

You have indexing string field with padding same like number. Apply Rang Query on String field but it's work like as number.

booleanQuery.must(qb.range().onField("currentCtc").below(25000).createQuery());

Apply Sorting on string field as number

SortField field = new SortField("currentCtc".trim(), SortField.DOUBLE,true);

Kurt Van den Branden
  • 11,995
  • 10
  • 76
  • 85
Bipin
  • 51
  • 3