Search code examples
phplaravelmeilisearch

Meilisearch or Eloquent queries?


I write api and use Laravel Scout + Meilisearch on my project. Everything is working. But I have some doubts about whether I am using meilisearch correctly. I would appreciate any help.

I know that it is possible to access meilisearch via localhost::7700 using Meilisearch\Client, as well as through the search method provided by the Searchable trait. In case I access it via the search method, like this:

$this->query = User::search($query, function ($meili_search, string $query, array $options) use ($request, $sort_field, $sort_direction) {
   $options['offset'] = PaginatorHelper::offset($request->page ?? 1, $request->per_page);
   $options['limit'] = intval($request->per_page);
   $options['sort'] = [$sort_field .':' . $sort_direction];

   return $meili_search->search($query, $options);
});

$this->query->get();

I see Eloquent queries in the telescope like:

select * from userswhereusers.id in (1, 2, 3)

But I don't understand why I see Eloquent queries if I request data via meilisearch? As if queries go to both meilisearch and mysql.

I expect data to be requested from meilisearch directly, bypassing Eloquent and the current behavior is confusing me.


Solution

  • Yes, you are using it correctly. When you use get(), first it gets ids from Meilisearch database and then call a query to the datable using whereIn.

    You can take a look, this is code of get method https://github.com/laravel/scout/blob/10.x/src/Builder.php#L286

    /**
     * Get the results of the search.
     *
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function get()
    {
        return $this->engine()->get($this);
    }
    

    It calls the get method of engine, in this case, MeilisearchEngine. MeilisearchEngine extends Engine. https://github.com/laravel/scout/blob/10.x/src/Engines/Engine.php#L133

    /**
     * Get the results of the given query mapped onto models.
     *
     * @param  \Laravel\Scout\Builder  $builder
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function get(Builder $builder)
    {
        return $this->map(
            $builder, $this->search($builder), $builder->model
        );
    }
    

    Within the map method, it calls getScoutModelsByIds method https://github.com/laravel/scout/blob/10.x/src/Engines/MeilisearchEngine.php#L264

     * Map the given results to instances of the given model.
     *
     * @param  \Laravel\Scout\Builder  $builder
     * @param  mixed  $results
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function map(Builder $builder, $results, $model)
    {
        if (is_null($results) || 0 === count($results['hits'])) {
            return $model->newCollection();
        }
    
        $objectIds = collect($results['hits'])->pluck($model->getScoutKeyName())->values()->all();
    
        $objectIdPositions = array_flip($objectIds);
    
        return $model->getScoutModelsByIds(
            $builder, $objectIds
        )->filter(function ($model) use ($objectIds) {
            return in_array($model->getScoutKey(), $objectIds);
        })->sortBy(function ($model) use ($objectIdPositions) {
            return $objectIdPositions[$model->getScoutKey()];
        })->values();
    }
    

    Within getScoutModelsByIds, it calls getScoutModelsByIds: https://github.com/laravel/scout/blob/10.x/src/Searchable.php#L224

    /**
     * Get the requested models from an array of object IDs.
     *
     * @param  \Laravel\Scout\Builder  $builder
     * @param  array  $ids
     * @return mixed
     */
    public function getScoutModelsByIds(Builder $builder, array $ids)
    {
        return $this->queryScoutModelsByIds($builder, $ids)->get();
    }
    

    And then, queryScoutModelsByIds builds query using whereIn:

    /**
     * Get a query builder for retrieving the requested models from an array of object IDs.
     *
     * @param  \Laravel\Scout\Builder  $builder
     * @param  array  $ids
     * @return mixed
     */
    public function queryScoutModelsByIds(Builder $builder, array $ids)
    {
        $query = static::usesSoftDelete()
            ? $this->withTrashed() : $this->newQuery();
    
        if ($builder->queryCallback) {
            call_user_func($builder->queryCallback, $query);
        }
    
        $whereIn = in_array($this->getKeyType(), ['int', 'integer']) ?
            'whereIntegerInRaw' :
            'whereIn';
    
        return $query->{$whereIn}(
            $this->qualifyColumn($this->getScoutKeyName()), $ids
        );
    }
    

    To get raw results just from Meilisearch, you can use raw method:

    $this->query->raw();