Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Highlight #28

Closed
medspec opened this issue Jun 21, 2019 · 10 comments
Closed

Highlight #28

medspec opened this issue Jun 21, 2019 · 10 comments

Comments

@medspec
Copy link

medspec commented Jun 21, 2019

Is there a way to add Highlight to search result?

@matchish
Copy link
Owner

You can use any feature provided by https://github.com/ongr-io/ElasticsearchDSL package
Here an example of using highlight https://stackoverflow.com/questions/56720692/add-highlight-using-ongr-io-elasticsearchdsl-package/56729546#56729546

Just put that code into callback of a search method

Product::search('title:this OR description:this) AND (title:that OR description:that', function ($client, Search $body) {
            $higlight = new Highlight();
            $higlight->addField('title');
            $body->addHighlight($higlight);
            return $client->search(['index' => 'products', 'body' => $body->toArray()]);
})->raw();

@ganicus
Copy link
Contributor

ganicus commented Aug 31, 2019

Is there a way to take this raw query and pass it back into a laravel collection that includes the highlights? Currently the raw query response places the "highlight" outside of the _source field that is aggregated into eloquent models via the map function in the custom scout engine.

@matchish
Copy link
Owner

You can implement your own EloquentHitsIteratorAggregate and pass raw results there.

$hits = new EloquentHitsIteratorAggregate($results, $builder->queryCallback);

I have plans to inject EloquentHitsIteratorAggregate using DI to be able to use different implementations, but now I'm working on another feature. Feel free to send PR)

@matchish
Copy link
Owner

matchish commented Nov 17, 2019

@booni3
Copy link

booni3 commented Feb 8, 2020

An example of merging highlights into a custom hits aggregator. It may not be best practice... but is working. Comments welcome.

public function getIterator()
{
    $hits = collect();
    if ($this->results['hits']['total']) {
        $raw = collect($this->results['hits']['hits']);
        $models = $this->collectModels($raw);
        $eloquentHits = $this->getEloquentHits($raw, $models);
        $hits = $this->mergeHighlightsIntoModels($eloquentHits, $raw);
    }

    return new \ArrayIterator($hits);
}

private function collectModels($rawHits)
{
    return collect($rawHits)->groupBy('_source.__class_name')
        ->map(function ($results, $class) {
            $model = new $class;
            $builder = new Builder($model, '');
            if (! empty($this->callback)) {
                $builder->query($this->callback);
            }
            /* @var Searchable $model */
            return $models = $model->getScoutModelsByIds(
                $builder, $results->pluck('_id')->all()
            );
        })
        ->flatten()->keyBy(function ($model) {
            return get_class($model).'::'.$model->getScoutKey();
        });
}

private function getEloquentHits($hits, $models)
{
    return collect($hits)->map(function ($hit) use ($models) {
        $key = $hit['_source']['__class_name'].'::'.$hit['_id'];
        return isset($models[$key]) ? $models[$key] : null;
    })->filter()->all();
}

private function mergeHighlightsIntoModels($eloquentHits, $raw)
{
    return collect($eloquentHits)->map(function(Model $eloquentHit) use($raw){
        $raw = collect($raw)
            ->where('_source.__class_name', get_class($eloquentHit))
            ->where('_source.id', $eloquentHit->id)
            ->first();

        foreach($raw['highlight'] ?? [] as $key => $highlight){
            $eloquentHit->setAttribute($key, $highlight[0]);
        }

        return $eloquentHit;
    })->all();
}

@XieXiaoSa
Copy link

Search results are sorted by ID but id is segmented. What should I do

@mondherinfo
Copy link

how can i add score to fields, best score will be in the begin

@matchish
Copy link
Owner

Learn it here https://github.com/ongr-io/ElasticsearchDSL

@mondherinfo
Copy link

Thank you

@fengci
Copy link

fengci commented Aug 11, 2022

@booni3 #28 (comment)

Hello, how do I use it?

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

No branches or pull requests

7 participants