1010
1111import org .apache .lucene .document .DoublePoint ;
1212import org .apache .lucene .document .FloatPoint ;
13+ import org .apache .lucene .document .InetAddressPoint ;
1314import org .apache .lucene .index .TermsEnum ;
1415import org .apache .lucene .sandbox .document .HalfFloatPoint ;
1516import org .apache .lucene .util .BytesRef ;
3233import org .opensearch .search .startree .filter .RangeMatchDimFilter ;
3334
3435import java .io .IOException ;
36+ import java .net .InetAddress ;
3537import java .util .ArrayList ;
3638import java .util .Comparator ;
3739import java .util .List ;
@@ -161,7 +163,9 @@ class Factory {
161163 org .opensearch .index .mapper .KeywordFieldMapper .CONTENT_TYPE ,
162164 new KeywordFieldMapper (),
163165 UNSIGNED_LONG .typeName (),
164- new UnsignedLongFieldMapperNumeric ()
166+ new UnsignedLongFieldMapperNumeric (),
167+ org .opensearch .index .mapper .IpFieldMapper .CONTENT_TYPE ,
168+ new IpFieldMapper ()
165169 );
166170
167171 public static DimensionFilterMapper fromMappedFieldType (MappedFieldType mappedFieldType , SearchContext searchContext ) {
@@ -406,25 +410,25 @@ Number getNextHigh(Number parsedValue) {
406410 }
407411}
408412
409- class KeywordFieldMapper implements DimensionFilterMapper {
413+ abstract class OrdinalFieldMapper implements DimensionFilterMapper {
414+
415+ abstract Object parseRawField (String field , Object rawValue , MappedFieldType mappedFieldType ) throws IllegalArgumentException ;
410416
411417 @ Override
412418 public DimensionFilter getExactMatchFilter (MappedFieldType mappedFieldType , List <Object > rawValues ) {
413- KeywordFieldType keywordFieldType = (KeywordFieldType ) mappedFieldType ;
414419 List <Object > convertedValues = new ArrayList <>(rawValues .size ());
415420 for (Object rawValue : rawValues ) {
416- convertedValues .add (parseRawKeyword (mappedFieldType .name (), rawValue , keywordFieldType ));
421+ convertedValues .add (parseRawField (mappedFieldType .name (), rawValue , mappedFieldType ));
417422 }
418423 return new ExactMatchDimFilter (mappedFieldType .name (), convertedValues );
419424 }
420425
421426 @ Override
422427 public DimensionFilter getRangeMatchFilter (MappedFieldType mappedFieldType , StarTreeRangeQuery rangeQuery ) {
423- KeywordFieldType keywordFieldType = (KeywordFieldType ) mappedFieldType ;
424428 return new RangeMatchDimFilter (
425429 mappedFieldType .name (),
426- parseRawKeyword (mappedFieldType .name (), rangeQuery .from (), keywordFieldType ),
427- parseRawKeyword (mappedFieldType .name (), rangeQuery .to (), keywordFieldType ),
430+ parseRawField (mappedFieldType .name (), rangeQuery .from (), mappedFieldType ),
431+ parseRawField (mappedFieldType .name (), rangeQuery .to (), mappedFieldType ),
428432 rangeQuery .includeLower (),
429433 rangeQuery .includeUpper ()
430434 );
@@ -484,8 +488,20 @@ public Optional<Long> getMatchingOrdinal(
484488 }
485489 }
486490
491+ @ Override
492+ public int compareValues (Object v1 , Object v2 ) {
493+ if (!(v1 instanceof BytesRef ) || !(v2 instanceof BytesRef )) {
494+ throw new IllegalArgumentException ("Expected BytesRef values for comparison" );
495+ }
496+ return ((BytesRef ) v1 ).compareTo ((BytesRef ) v2 );
497+ }
498+ }
499+
500+ class KeywordFieldMapper extends OrdinalFieldMapper {
501+
487502 // TODO : Think around making TermBasedFT#indexedValueForSearch() accessor public for reuse here.
488- private Object parseRawKeyword (String field , Object rawValue , KeywordFieldType keywordFieldType ) {
503+ Object parseRawField (String field , Object rawValue , MappedFieldType mappedFieldType ) {
504+ KeywordFieldType keywordFieldType = (KeywordFieldType ) mappedFieldType ;
489505 Object parsedValue = null ;
490506 if (rawValue != null ) {
491507 if (keywordFieldType .getTextSearchInfo ().getSearchAnalyzer () == Lucene .KEYWORD_ANALYZER ) {
@@ -499,12 +515,51 @@ private Object parseRawKeyword(String field, Object rawValue, KeywordFieldType k
499515 }
500516 return parsedValue ;
501517 }
518+ }
502519
503- @ Override
504- public int compareValues (Object v1 , Object v2 ) {
505- if (!(v1 instanceof BytesRef ) || !(v2 instanceof BytesRef )) {
506- throw new IllegalArgumentException ("Expected BytesRef values for keyword comparison" );
520+ /**
521+ * This class provides functionality to map IP address values for exact and range-based
522+ * filtering within a Star-Tree index. It handles the conversion of IP address
523+ * objects into sortable {@link BytesRef}.
524+ */
525+ class IpFieldMapper extends OrdinalFieldMapper {
526+
527+ /**
528+ * Parses a raw IP address value into a sortable {@link BytesRef}.
529+ *
530+ * This method handles various input types, including {@link InetAddress}, {@link BytesRef},
531+ * and {@link String}, converting them into a binary representation using
532+ * {@link InetAddressPoint#encode(InetAddress)}.
533+ *
534+ * @param field The name of the field being processed.
535+ * @param rawValue The raw IP address value.
536+ * @return A {@link BytesRef} representation of the IP address, or null if the input is null.
537+ */
538+ Object parseRawField (String field , Object rawValue , MappedFieldType mappedFieldType ) throws IllegalArgumentException {
539+ Object parsedValue = null ;
540+ if (rawValue != null ) {
541+ try {
542+ switch (rawValue ) {
543+ case InetAddress inetAddress -> {
544+ parsedValue = new BytesRef (InetAddressPoint .encode (inetAddress ));
545+ }
546+ case BytesRef bytesRef -> {
547+ return bytesRef ;
548+ }
549+ case String s -> {
550+ InetAddress addr = InetAddress .getByName (s );
551+ parsedValue = new BytesRef (InetAddressPoint .encode (addr ));
552+ }
553+ default -> {
554+ throw new IllegalArgumentException (
555+ "Unsupported value type for IP field [" + field + "]: " + rawValue .getClass ().getName ()
556+ );
557+ }
558+ }
559+ } catch (Exception e ) {
560+ throw new IllegalArgumentException ("Failed to parse IP value for field [" + field + "]" , e );
561+ }
507562 }
508- return (( BytesRef ) v1 ). compareTo (( BytesRef ) v2 ) ;
563+ return parsedValue ;
509564 }
510565}
0 commit comments