Skip to content

Handle fractional numbers in Qdrant filter converter - #6981

Open
Lubaoshuai wants to merge 1 commit into
spring-projects:mainfrom
Lubaoshuai:fix/qdrant-fractional-number-filter
Open

Lubaoshuai wants to merge 1 commit into
spring-projects:mainfrom
Lubaoshuai:fix/qdrant-fractional-number-filter

Conversation

@Lubaoshuai

Copy link
Copy Markdown
Contributor

QdrantFilterExpressionConverter converted numeric filter values with Long.parseLong(value.toString()), so any fractional number crashed the whole search with a NumberFormatException:

new SearchRequest().withFilterExpression(new Eq("price", 10.5));
// NumberFormatException: For input string: "10.5"

Whole doubles failed the same way (Eq("rating", 5.0)"5.0" is not parseable as a long), and large floats crashed via scientific notation (1.0E7).

Changes

  • buildEqCondition / buildNeCondition: integral numbers (Integer, Long, Short, Byte) are matched as longs directly from Number.longValue() without the string round-trip; fractional numbers are expressed as an inclusive range condition (gte = lte), since the Qdrant client's ConditionFactory only offers exact-match conditions for strings, longs and booleans; Boolean values are now matched as booleans instead of being rejected.
  • buildInCondition / buildNInCondition: list members are converted via Number.longValue(), and a fractional member is rejected with a clear IllegalStateException (Qdrant's values-match has no float variant) instead of the previous NumberFormatException.

How tested

New QdrantFilterExpressionConverterTests (8 cases, plain JUnit, no Testcontainers) asserting the generated gRPC condition: EQ/NE with fractional numbers produce an inclusive Range(gte = lte), EQ with integral numbers/booleans produce the corresponding Match, IN/NIN with integral lists produce integer matches, and a fractional IN member raises a clear error.

./mvnw -am -pl vector-stores/spring-ai-qdrant-store test passes (module: 44 tests, 0 failures).

Eq/Ne/In/Nin filter expressions converted numeric values with
Long.parseLong(value.toString()), which threw NumberFormatException for
any fractional number (e.g. Eq("price", 10.5)) and mishandled whole
doubles such as 5.0. Exact matches on fractional numbers are now
expressed as an inclusive range condition, integral numbers are matched
as longs without a string round-trip, and booleans are matched as
booleans. In/Nin lists reject fractional members with a clear exception
instead of an unparseable-number failure.

Signed-off-by: Lubaoshuai <128781758+Lubaoshuai@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants