Skip to content

feat: add personalize search parameter to SearchQuery#918

Open
tcferreira wants to merge 3 commits into
meilisearch:mainfrom
tcferreira:feat/personalize-search
Open

feat: add personalize search parameter to SearchQuery#918
tcferreira wants to merge 3 commits into
meilisearch:mainfrom
tcferreira:feat/personalize-search

Conversation

@tcferreira

@tcferreira tcferreira commented Jun 20, 2026

Copy link
Copy Markdown

Summary

Meilisearch v1.47.0 adds experimental personalized search. This adds support for
the new personalize search parameter ({ "userContext": "..." }) to the typed
SearchQuery builder. Closes #917.

Changes

  • New PersonalizeOptions contract with setUserContext(), mirroring
    HybridSearchOptions.
  • SearchQuery::setPersonalize(PersonalizeOptions), serialized into the search
    payload through toArray() (used by multiSearch / federated search). The
    array-based search() path already forwards arbitrary parameters, so it needs
    no change.
  • Contract tests for PersonalizeOptions and SearchQuery::setPersonalize.

Example

$client->multiSearch([
    (new SearchQuery())
        ->setIndexUid('movies')
        ->setQuery('shifu')
        ->setPersonalize((new PersonalizeOptions())->setUserContext('The user prefers science fiction')),
]);

Testing

composer lint passes. Added contract tests for PersonalizeOptions and
SearchQuery::setPersonalize; they assert the serialized payload and don't
require a running Meilisearch instance.

Overview

This PR adds support for personalized search (experimental in Meilisearch v1.47.0) to the PHP SDK’s typed SearchQuery builder, allowing a userContext string to be attached to search requests.

Changes

New Contract: PersonalizeOptions

A new Meilisearch\Contracts\PersonalizeOptions contract was introduced (src/Contracts/PersonalizeOptions.php) to model personalization settings. It provides:

  • setUserContext(string $userContext): self (fluent setter)
  • toArray(): array to serialize the payload, omitting unset values

PersonalizeOptions is implemented as a final class.

Enhanced SearchQuery

The Meilisearch\Contracts\SearchQuery contract now supports personalization by adding:

  • a private ?PersonalizeOptions $personalize field
  • setPersonalize(PersonalizeOptions $personalize): self

SearchQuery::toArray() was updated to include an optional personalize entry shaped like { userContext?: non-empty-string }, serialized via PersonalizeOptions->toArray(). When personalize is not set, the field is omitted from the payload (with serialization simplified using PHP’s nullsafe operator).

This serialized payload is used by request flows that rely on typed query serialization (e.g., multiSearch and federated search).

Test Coverage

  • tests/Contracts/PersonalizeOptionsTest.php validates PersonalizeOptions::toArray() for both empty and populated userContext.
  • tests/Contracts/SearchQueryTest.php adds coverage for SearchQuery::setPersonalize() ensuring the serialized personalize.userContext is present in toArray().

Resolution

Implements the requested SDK support for personalized search introduced in Meilisearch v1.47.0 (fixing issue #917).

Meilisearch v1.47.0 adds experimental personalized search: the search
endpoints now accept a `personalize` object with a `userContext` string.

Add a `PersonalizeOptions` contract (mirroring `HybridSearchOptions`) and a
`SearchQuery::setPersonalize()` builder method, serialized into the search
payload through `toArray()`. The plain `search()` path already forwards
arbitrary parameters, so it needs no change.

Adds contract tests for `PersonalizeOptions` and `SearchQuery::setPersonalize`.

Closes meilisearch#917
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 304a811f-7de9-4bbf-a0ed-8ca1645669f5

📥 Commits

Reviewing files that changed from the base of the PR and between 1a75c3f and 193e045.

📒 Files selected for processing (2)
  • src/Contracts/PersonalizeOptions.php
  • src/Contracts/SearchQuery.php
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Contracts/PersonalizeOptions.php
  • src/Contracts/SearchQuery.php

📝 Walkthrough

Walkthrough

A new PersonalizeOptions contract class is added with a nullable userContext field, a fluent setUserContext setter, and a toArray() serializer. SearchQuery gains a personalize property, a setPersonalize() setter, and updated toArray() output to include the personalize payload. Unit tests cover both new contracts.

Changes

Personalized Search

Layer / File(s) Summary
PersonalizeOptions contract
src/Contracts/PersonalizeOptions.php, tests/Contracts/PersonalizeOptionsTest.php
Introduces PersonalizeOptions with a nullable userContext property, a fluent setUserContext() setter, and a toArray() serializer that omits null entries. Tests verify empty-options and set-userContext behavior.
SearchQuery integration
src/Contracts/SearchQuery.php, tests/Contracts/SearchQueryTest.php
Adds a personalize property to SearchQuery, a setPersonalize(PersonalizeOptions) fluent setter, extends the toArray() PHPDoc return shape, and serializes the personalize payload into the output. The new testSetPersonalize() test validates the full round-trip.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related issues

Poem

🐇 A new little field hops into the fray,
userContext now brightens the search each day.
PersonalizeOptions neatly in tow,
Through toArray() the preferences flow.
The bunny typed tests — they all turn green!
The cleanest search contract a rabbit has seen. 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding personalize search parameter support to SearchQuery.
Linked Issues check ✅ Passed The PR implements all coding requirements from issue #917: PersonalizeOptions contract, SearchQuery::setPersonalize() method, and comprehensive test coverage for serialization.
Out of Scope Changes check ✅ Passed All changes are directly related to adding personalized search support; no extraneous modifications outside the scope of issue #917 are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Contracts/SearchQuery.php`:
- Around line 491-492: The `toArray()` method documentation in SearchQuery.php
uses a weak type annotation `personalize?: array<mixed>` for the personalize
parameter at line 492, which violates the coding guideline to use precise
PHPStan array shapes. Examine the `PersonalizeOptions::toArray()` method to
determine its exact return shape, then replace the generic `array<mixed>` type
with the precise shape that PersonalizeOptions::toArray() actually returns in
the PHPDoc comment for the toArray() method.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c6af0bca-9a25-4d19-b9d0-af37e9f3dea4

📥 Commits

Reviewing files that changed from the base of the PR and between c651751 and d09f57e.

📒 Files selected for processing (4)
  • src/Contracts/PersonalizeOptions.php
  • src/Contracts/SearchQuery.php
  • tests/Contracts/PersonalizeOptionsTest.php
  • tests/Contracts/SearchQueryTest.php

Comment thread src/Contracts/SearchQuery.php Outdated
Comment thread src/Contracts/SearchQuery.php Outdated
'rankingScoreThreshold' => $this->rankingScoreThreshold,
'distinct' => $this->distinct,
'federationOptions' => null !== $this->federationOptions ? $this->federationOptions->toArray() : null,
'personalize' => null !== $this->personalize ? $this->personalize->toArray() : null,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'personalize' => null !== $this->personalize ? $this->personalize->toArray() : null,
'personalize' => $this->personalize?->toArray(),

Comment thread src/Contracts/PersonalizeOptions.php Outdated

namespace Meilisearch\Contracts;

class PersonalizeOptions

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class PersonalizeOptions
final class PersonalizeOptions

Address review feedback: simplify personalize serialization with the nullsafe
operator and mark PersonalizeOptions as final.
@tcferreira

Copy link
Copy Markdown
Author

Thanks for the review @norkunas! Applied both suggestions: personalize is now serialized with the nullsafe operator, and PersonalizeOptions is marked final.

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.44%. Comparing base (0078a8c) to head (193e045).
⚠️ Report is 157 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #918      +/-   ##
==========================================
- Coverage   89.78%   88.44%   -1.34%     
==========================================
  Files          59       93      +34     
  Lines        1449     1939     +490     
==========================================
+ Hits         1301     1715     +414     
- Misses        148      224      +76     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@norkunas norkunas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, lgtm

@norkunas

Copy link
Copy Markdown
Collaborator

@Strift we need to fix phpstan, new version prints many errors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Meilisearch v1.47.0] Add personalized search (experimental)

2 participants