Skip to main content

Example solution: `/info`, `/search` and `/movie/{movie_id}` endpoints

Here are example solutions for the first three endpoints, with explanations of key concepts and implementation decisions.

Endpoint 1: /info - Dataset Information

Example Solution

@app.get("/info", response_model=InfoResponse)
def get_dataset_info():
"""
Get basic information about the dataset
- Total movie count
- Some example movies
"""
try:
with connect_to_weaviate() as client:
movies = client.collections.use(CollectionName.MOVIES)
movies_count = len(movies)
sample_movies_response = movies.query.fetch_objects(limit=5).objects
sample_movies = [o.properties for o in sample_movies_response]

return InfoResponse(movies_count=movies_count, sample_movies=sample_movies)

except Exception as e:
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")

Key Points

  • len(collection): Efficiently get the total count
  • fetch_objects(): Returns objects with additional metadata (e.g. UUID); and we extract .properties
  • Context manager: with connect_to_weaviate() handles connection cleanup automatically
  • Error handling: The try/catch provides graceful error responses

Endpoint 2: /search - Hybrid Search with Filtering

Example Solution

@app.get("/search", response_model=SearchResponse)
def search_movies(
q: str = Query(..., description="Search query for movies"),
page: int = Query(1, ge=1, le=10, description="Page number (1-10)"),
year_min: Optional[int] = Query(
None, description="Filter by release year - from this year"
),
year_max: Optional[int] = Query(
None, description="Filter by release year - to this year"
),
):
"""
Search for movies using hybrid search
- Return 20 movies per page
- Support pagination, up to 10 pages
- Optional year filtering
"""
try:
if page >= 1:
offset = PAGE_SIZE * (page - 1)

filters = None
if year_min and year_max:
filters = (
Filter.by_property("year").greater_or_equal(year_min)
& Filter.by_property("year").less_or_equal(year_max)
)
elif year_min:
filters = Filter.by_property("year").greater_or_equal(year_min)
elif year_max:
filters = Filter.by_property("year").less_or_equal(year_max)

with connect_to_weaviate() as client:
movies = client.collections.use(CollectionName.MOVIES)
response = movies.query.hybrid(
query=q,
offset=offset,
limit=PAGE_SIZE,
filters=filters,
target_vector="default",
)

return SearchResponse(
movies=[o.properties for o in response.objects],
current_page=page,
)

except Exception as e:
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")

Key Concepts

Hybrid search: Combines vector similarity (target_vector="default") with keyword matching for the best of both worlds.

Filter logic: Three cases handled:

  • Both min and max: Combined with & operator
  • Min only: Single greater-or-equal filter
  • Max only: Single less-or-equal filter
  • Neither: filters=None (no filtering)

Pagination: Calculate offset based on page size to skip already-seen results.

Target vector: Specifies which vector to search for the semantic component of hybrid search.

Endpoint 3: /movie/{movie_id} - Movie Details and Similarity

Example Solution

@app.get("/movie/{movie_id}", response_model=MovieDetailResponse)
def get_movie_details(movie_id: str):
"""
Get detailed information about a specific movie, using the Weaviate object UUID
- Returns movie metadata
- Returns top 15 most similar movies
"""
try:
with connect_to_weaviate() as client:
movies = client.collections.use(CollectionName.MOVIES)
movie = movies.query.fetch_objects(
filters=Filter.by_property("movie_id").equal(int(movie_id)), limit=1
).objects[0]

response = movies.query.near_object(
near_object=movie.uuid, target_vector="default", limit=PAGE_SIZE
)
similar_movies = [
o.properties for o in response.objects[1:] # Exclude itself
]

return MovieDetailResponse(
movie=movie.properties, similar_movies=similar_movies
)

except Exception as e:
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")

Key Concepts

Property filtering: Use equal() to find objects by specific field values. Note the type conversion to int(movie_id) to match the expected type.

Near-object search: Uses the object's UUID to find similar items.

UUID usage: Weaviate uses UUIDs as the unique object identifier in each collection. The movie.uuid gives you direct access.

Result exclusion: Near-object search includes the original object as the first result (distance 0), so we skip it with [1:].

Understanding the Patterns

These three endpoints demonstrate core patterns you'll use throughout Weaviate applications:

  1. Collection access: Fetch (.use()) the collection first, then perform operations
  2. Query response management: Each query includes a .objects attribute; each of which includes properties (.properties) and metadata (e.g. uuid / vectors if requested)
  3. Filter construction: Construct filters step-by-step for complex conditions
  4. Vector targeting: Specify which vector to use for different search strategies
  5. Error handling: Wrap operations in try/catch for robust APIs
What's next?

Now that you've mastered the fundamentals, let's implement the more advanced endpoints that demonstrate targeted vector search and AI-powered recommendations using RAG.

Login to track your progress