필터
필터 (Filters)
검색 결과를 그냥 받기보다, 특정 조건에 맞는 객체만 포함하거나 제외하고 싶을 때가 있죠. 필터는 바로 그 일을 합니다. 벡터 검색·키워드 검색·하이브리드 검색 어디에나 붙일 수 있어서, 결과 집합을 원하는 대로 좁히는 가장 기본적인 도구예요.
필터 연산자 전체 목록은 API 레퍼런스 페이지에서 확인할 수 있습니다.
출처: 공식문서
단일 조건 필터
쿼리에 filter 하나를 추가해 결과 집합을 제한합니다.
from weaviate.classes.query import Filter
jeopardy = client.collections.use("JeopardyQuestion")
response = jeopardy.query.fetch_objects(
filters=Filter.by_property("round").equal("Double Jeopardy!"),
limit=3
)
여러 조건 필터
두 개 이상의 조건을 조합할 때는 조건 간 관계를 And, Or, Not으로 정의합니다.
v4 파이썬 클라이언트는 any_of/all_of와 함께 &(AND), |(OR) 연산자도 제공해요.
# `&` / `|` 연산자로 쌍 조합
filters=(
Filter.by_property("round").equal("Double Jeopardy!") &
Filter.by_property("points").less_than(600) &
Filter.not_(Filter.by_property("answer").equal("Yucatan"))
)
# any_of: 아래 중 하나라도 만족하면 매칭 (| 로 결합)
filters=(
Filter.any_of([
Filter.by_property("points").greater_or_equal(700),
Filter.by_property("points").less_than(500),
Filter.by_property("round").equal("Double Jeopardy!"),
])
)
# all_of: 아래를 모두 만족해야 매칭 (& 로 결합)
filters=(
Filter.all_of([
Filter.by_property("points").greater_than(300),
Filter.by_property("points").less_than(700),
Filter.by_property("round").equal("Double Jeopardy!"),
])
)
JS/TS v3 API에서는 Filters.and/Filters.or 메서드로 조합하고, Filters.not으로 논리 부정을 씁니다. 가변 인자를 받으므로 배열은 전개(spread)해서 넘겨야 해요(Filters.and(...fs)).
And/Or로 조건 그룹핑·중첩
복합 논리를 표현하려면 And/Or 연산자로 조건을 그룹핑하고 중첩합니다.
response = jeopardy.query.fetch_objects(
filters=Filter.by_property("answer").like("*bird*") &
(Filter.by_property("points").greater_than(700) | Filter.by_property("points").less_than(300)),
limit=3
)
중첩 필터를 만들려면: 바깥 operator를 And/Or로 설정 → operands 추가 → operand 안에서 operator를 And/Or로 설정해 중첩 그룹 추가 → 필요한 만큼 operands 추가.
검색 연산자와 결합
필터는 nearXXX, hybrid, bm25 같은 검색 연산자와 함께 동작합니다.
response = jeopardy.query.near_text(
query="fashion icons",
filters=Filter.by_property("points").greater_than(200),
limit=3
)
ContainsAny · ContainsAll · ContainsNone
이 연산자들은 텍스트 프로퍼티에 값 배열을 입력으로 받습니다.
ContainsAny: 프로퍼티가 배열 값 중 하나라도(하나 이상) 포함하면 매칭.ContainsAll: 프로퍼티가 배열 값을 전부 포함하면 매칭.ContainsNone: 프로퍼티가 배열 값 중 아무것도 포함하지 않으면 매칭.
token_list = ["australia", "india"]
response = jeopardy.query.fetch_objects(
filters=Filter.by_property("answer").contains_any(token_list),
limit=3
)
token_list = ["blue", "red"]
response = jeopardy.query.fetch_objects(
filters=Filter.by_property("question").contains_all(token_list),
limit=3
)
부분 일치(Like) 필터
객체 프로퍼티가 text거나 object ID 같은 text-유사 데이터 타입이면, Like로 부분 텍스트 매칭을 할 수 있어요.
response = jeopardy.query.fetch_objects(
filters=Filter.by_property("answer").like("*ala*"),
limit=3
)
*와일드카드는 0개 이상 문자를 매칭합니다.?는 정확히 1개 문자를 매칭합니다.- 현재
Like필터는 와일드카드 자체(?,*)를 리터럴 문자로는 매칭하지 못합니다.
크로스 레퍼런스로 필터링
크로스 레퍼런스된 객체의 프로퍼티로 필터링하려면, 필터에 컬렉션 이름을 추가합니다.
from weaviate.classes.query import Filter, QueryReference
response = jeopardy.query.fetch_objects(
filters=Filter.by_ref(link_on="hasCategory").by_property("title").like("*Sport*"),
return_references=QueryReference(link_on="hasCategory", return_properties=["title"]),
limit=3
)
지리 좌표로 필터
지리 좌표 프로퍼티는 within_geo_range로 반경 필터링합니다. 거리 단위는 미터예요.
from weaviate.classes.query import GeoCoordinate
response = publications.query.fetch_objects(
filters=(
Filter
.by_property("headquartersGeoLocation")
.within_geo_range(
coordinate=GeoCoordinate(latitude=52.39, longitude=4.84),
distance=1000 # meters
)
)
)
DATE 데이터 타입으로 필터
DATE 타입 프로퍼티는 RFC 3339 타임스탬프 또는 Python datetime 같은 클라이언트 호환 타입으로 지정합니다.
from datetime import datetime, timezone
filter_time = datetime(2022, 6, 10).replace(tzinfo=timezone.utc)
# RFC 3339 문자열도 가능: filter_time = "2022-06-10T00:00:00.00Z"
response = collection.query.fetch_objects(
limit=3,
filters=Filter.by_property("some_date").greater_than(filter_time),
)
메타데이터로 필터
필터는 object id, 프로퍼티 길이, 타임스탬프 같은 메타데이터 프로퍼티에서도 동작합니다.
객체 id 기준
target_id = "00037775-1432-35e5-bc59-443baaef7d80"
response = collection.query.fetch_objects(
filters=Filter.by_id().equal(target_id)
)
객체 타임스탬프 기준
이 필터는 property timestamp 인덱싱이 필요합니다.
filter_time = datetime(2020, 1, 1).replace(tzinfo=timezone.utc)
response = collection.query.fetch_objects(
limit=3,
filters=Filter.by_creation_time().greater_than(filter_time),
return_metadata=MetadataQuery(creation_time=True)
)
프로퍼티 길이 기준
property length 인덱싱이 필요합니다.
length_threshold = 20
response = collection.query.fetch_objects(
limit=3,
filters=Filter.by_property("answer", length=True).greater_than(length_threshold),
)
null 상태 기준
property null state 인덱싱이 필요합니다.
response = collection.query.fetch_objects(
limit=3,
filters=Filter.by_property("country").is_none(True) # country가 null인 객체 찾기
)
중첩 객체 프로퍼티 필터링
:::caution 프리뷰 기능
Weaviate v1.38부터 프리뷰로 제공되며, 서버에서 WEAVIATE_PREVIEW_NESTED_FILTERING=on 환경변수로 켭니다. 경로 문법과 연산자 의미는 안정적이지만 GA 전에 디스크 인코딩이 바뀔 수 있어요.
:::
object/object[] 프로퍼티는 자체 중첩 스키마를 가집니다. 중첩 객체 안의 값을 필터링하려면 부모 프로퍼티에서 비교할 리프까지 내려가는 점(.) 구분 단일 경로를 사용합니다.
[N]은 세그먼트를 배열 인덱스(0부터)에 고정합니다.
| 경로 | 의미 |
|---|---|
cars.make |
cars 배열의 어떤 요소든 make를 가지면 매칭 |
cars[0].make |
첫 번째 차의 make (위치 고정) |
cars.tires.width |
어떤 차의 어떤 타이어든 (두 단계 object[] 재귀) |
cars[1].tires[2].brand |
두 번째 차의 세 번째 타이어 brand |
[N]이 붙은 세그먼트는object[](배열)여야 해요.- 중간 모든 세그먼트는
object또는object[]여야 하며 스칼라를 통한 피벗은 불가능합니다. - 리프는 지원되는 스칼라 타입이면 무엇이든 가능합니다.
- 두 리프 필터를
And로 결합하면 부모 배열의 같은 요소가 두 조건을 모두 만족해야 매칭됩니다. (요소 상관관계) object/object[]세그먼트를 가리키는 경로는IsNull과만 유효합니다(하위 객체 존재 여부).
제한 사항
- 리프 데이터 타입:
text,int,number,boolean,date,uuid와 배열 변형.blob,blobHash,geoCoordinates,phoneNumber, 크로스 레퍼런스(cref)는 중첩 필터링에 허용되지 않습니다. IndexFilterable필요: 중첩 필터링은 각 리프의 filterable 역파일 인덱스를 사용해요.IndexRangeFilters/IndexSearchable플래그는 아직 중첩 검색기에서 사용되지 않습니다.- 토큰화 중요: 중첩
text리프도 플랫 프로퍼티와 같은 토큰화 옵션을 사용해요. 이름·코드·식별자 정확 일치 필터는 리프에tokenization: field를 설정하세요. - 참조 경로 vs 중첩 경로: 참조 경로 필터는 여러 요소
Path(["inCity", "City", "name"])이고, 중첩 경로는 단일 요소 경로(점 포함,["cars.make"])입니다.
필터 성능 개선
필터가 느리면 limit 파라미터를 추가하거나 where 연산자를 추가해 데이터셋 크기를 제한해 보세요.