teamtnt / laravel-scout-tntsearch-driver

Driver for Laravel Scout search package based on https://github.com/teamtnt/tntsearch
MIT License
1.1k stars 144 forks source link

Boolean search with Scout driver #28

Closed GaspariLab closed 7 years ago

GaspariLab commented 8 years ago

Hi!

Is there a way to use the searchBoolean method using the Scout driver?

nticaric commented 8 years ago

Currently it's not possible, guess we should add it to the config file

simpledev commented 7 years ago

searchBoolean would be very useful for me and I think for many other developers

raphaelbeckmann commented 7 years ago

This is necessary indeed. Currently searches like "Bugs Bunny" will return all entries with "Bugs" and all items with "Bunny" in it.

nticaric commented 7 years ago

Since this is currently not available in the package you can use a workaround and call the searchBoolean method directly, something like:

$tnt = new TNTSearch;
$driver = config('database.default');
$config = config('scout.tntsearch') + config("database.connections.$driver");
$tnt->loadConfig($config);
$tnt->setDatabaseHandle(app('db')->connection()->getPdo());
$tnt->selectIndex("users.index");
$res  = $tnt->searchBoolean("Bugs Bunny", 12);
$keys = collect($res['ids'])->values()->all();

$users = User::whereIn('id', $keys)->get();

If you pack this into a method it's simple to reuse it when you need it.

raphaelbeckmann commented 7 years ago

Works, thank you!

marksparrish commented 7 years ago

I would like the same functionality. Could you add add option the the search method to indicate you want a boolean search? I tweaked the performSearch method and changed the return to searchBoolean and this worked as I wanted but now I loose the other search option. This works for this application because I only need all word matches (boolean).

    protected function performSearch(Builder $builder, array $options = [])
    {
        $index = $builder->index ?: $builder->model->searchableAs();
        $limit = $builder->limit ?: 10000;
        $this->tnt->selectIndex("{$index}.index");

        $this->builder = $builder;
        $this->tnt->asYouType = $builder->model->asYouType ?: false;

        if ($builder->callback) {
            return call_user_func(
                $builder->callback,
                $this->tnt,
                $builder->query,
                $options
            );
        }

        return $this->tnt->searchBoolean($builder->query, $limit);
    }

I tried to add an additional parameter to the Scout search method but it will only accept one parameter. I think we might need to request that the Scout package add the ability to pass additional parameters.

$orders = App\Order::search('Star Trek', true)->get();

Mark

marksparrish commented 7 years ago

Looks like you can already. Just need pass an array instead of a search string.

https://stackoverflow.com/questions/39541603/how-can-you-set-boosts-and-filters-with-laravel-scout-and-elasticsearch

Here would be the updated performSearch method in TNTSearchEngine.php

$query = [
    'query' => 'Star Trek',
    'exact' => true,
];

$orders = App\Order::search($query)->get();

    protected function performSearch(Builder $builder, array $options = [])
    {
        // if an array then expects two keys - query [string], exact [boolean]
        if (is_array($builder->query)) {
            $builder->exact = $builder->query['exact'];
            $builder->query = $builder->query['query'];
        } else {
            $builder->exact = false;
        }

        $index = $builder->index ?: $builder->model->searchableAs();
        $limit = $builder->limit ?: 10000;
        $this->tnt->selectIndex("{$index}.index");

        $this->builder = $builder;
        $this->tnt->asYouType = $builder->model->asYouType ?: false;

        if ($builder->callback) {
            return call_user_func(
                $builder->callback,
                $this->tnt,
                $builder->query,
                $options
            );
        }

        return $builder->exact ? $this->tnt->searchBoolean($builder->query, $limit) : $this->tnt->search($builder->query, $limit);
    }
marksparrish commented 7 years ago

OK - was working this some more to see if I could also get the geoSearch working. You will need to implement the geoIndexing outside of the searchable trait. Follow the instructions at https://github.com/teamtnt/tntsearch


    protected function performSearch(Builder $builder, array $options = [])
    {
        // tests $builder->query is an array 
        $queryType = is_array($builder->query) ? $builder->query['type'] : false;

        $index = $builder->index ?: $builder->model->searchableAs();
        $limit = $builder->limit ?: 10000;
        $this->tnt->selectIndex("{$index}.index");
        $config = $this->tnt->config;
        $this->builder = $builder;
        $this->tnt->asYouType = $builder->model->asYouType ?: false;

        if ($builder->callback) {
            return call_user_func(
                $builder->callback,
                $this->tnt,
                $builder->query,
                $options
            );
        }
        switch ($queryType) {
            case 'geo':
                // $builder->query should be passed as an array 
                // $params = [
                //  'locaton' => [
                //      'longitude' => $lng [float]
                //      'latitude' => $lat [float]
                //  ],
                //  'distance' => $distance [float]
                //  'limit' => $limit [integer] [optional]
                // ];
                $location = $builder->query['location'];
                $distance = $builder->query['distance'];
                $limit = array_key_exists('limit', $builder->query) ? $builder->query['limit'] : 10;
                $this->tnt = new TNTGeoSearch();
                $this->tnt->loadConfig($config);
                $this->tnt->selectIndex("{$index}.index");
                return $this->tnt->findNearest($location, $distance, $limit);
                break;
            case 'boolean':
                // $builder->query should be passed as an array 
                // $params = [
                //  'query' => $query [string]
                //  'limit' => $limit [integer] [optional]
                // ];
                $query = $builder->query['query'];
                $limit = array_key_exists('limit', $builder->query) ? $builder->query['limit'] : $limit;
                return $this->tnt->searchBoolean($query, $limit);
                break;
            default:
                return $this->tnt->search($builder->query, $limit);
                break;
        }
    }
dominiquedutra commented 7 years ago

This should do: https://github.com/teamtnt/laravel-scout-tntsearch-driver/pull/103

dominiquedutra commented 7 years ago

@nticaric would you mind tagging a release with the latest commit?

Best regards,

nticaric commented 7 years ago

@dominiquedutra sure, no problem