la-haute-societe / craft-elasticsearch

Bring the power of Elasticsearch to your Craft CMS projects
Other
18 stars 14 forks source link

Optimise search results #6

Open ray-001 opened 5 years ago

ray-001 commented 5 years ago

Hi,

I'm considering using this plugin for one of our clients but I have two questions regarding features of ElasticSearch what needs to be a key feature in our applications:

- Is it possible to make the search queries Fuzzy (not exact matching) -- https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#fuzziness Edit: It's possible to hook upon the before search event to trigger extra param for fuzziness

       Event::on(ElasticsearchRecord::class, ElasticsearchRecord::EVENT_BEFORE_SEARCH, function (SearchEvent $event) {
            /** @var ElasticsearchRecord $esRecord */
            $esRecord = $event->sender;
            $query = $event->query;
            // Customise the query params
            $queryParams = $esRecord->getQueryParams($query);
            $queryParams['multi_match']['fuzziness'] = "AUTO";
            $esRecord->setQueryParams($queryParams);
        });

Should be great to have the option available in craft.elasticsearch.search() function though.

Kind regards, Raymond

juban commented 5 years ago

Hi @ray-001 ,

Sorry for the late answer. For the fuzziness, indeed, you found the right way to do it. We are considering adding a parameter to the search method in an upcoming release. For the pagination, I'll get back to you a soon as possible with a solution.

Thanks.

juban commented 5 years ago

Hi @ray-001 ,

Regarding the pagination, you could implement something like the following:

{% extends "_layout" %}
{% set title = "Search" %}
{% set results = craft.elasticsearch.search(craft.app.request.get('q')) %}

{% set resultsDataProvider = create({'class': 'yii\\data\\ArrayDataProvider', 'allModels':results, 'pagination': {'pageSize': 10}}) %} {# adjust pageSize to the expected number of items per page #}
{% set results = resultsDataProvider.getModels() %}
{% set currentPage = resultsDataProvider.getPagination().getPage() + 1 %}
{% set pageCount = resultsDataProvider.getPagination().getPageCount() %}
{% if currentPage > 1 %}
    {% set prevPage = currentPage - 1 %}
{% endif %}
{% if currentPage < pageCount %}
    {% set nextPage = currentPage + 1 %}
{% endif %}

{% block content %}

    <h1>{{ "Search"|t }}</h1>

    <form action="{{ url('search') }}">
        <input type="search" name="q" placeholder="Search" value="{{ craft.app.request.get('q') }}">
        <input type="submit" value="Go">
    </form>

    {% if results|length %}

        <h2>{{ "Results"|t }}</h2>

        {% for result in results %}
            <h3>{{ result.title }}</h3>
            <p>
                <small><a href="{{ result.url|raw }}">{{ result.url }}</a><br/>
                    {% if result.highlights|length %}
                        {% for highlight in result.highlights %}
                            {{ highlight|raw }}<br/>
                        {% endfor %}
                    {% endif %}
                </small>
            </p>
            <hr>
        {% endfor %}
        {% if prevPage is defined %}<a href="{{ url(craft.request.url, {'q': craft.app.request.get('q'), 'page': prevPage}) }}">Previous Page</a>{% endif %}
        {% if nextPage is defined %}<a href="{{ url(craft.request.url, {'q': craft.app.request.get('q'), 'page': nextPage}) }}">Next Page</a>{% endif %}

    {% else %}
        {% if craft.app.request.get('q') is not null %}
            <p>
                <em>{{ "No results"|t }}</em>
            </p>
        {% endif %}
    {% endif %}

{% endblock %}

This may not be the perfect solution, but it works pretty well. We will implement a method to pass the search result as a query object to the native paginate Twig tag in the future.

I hope the answer suits you.

Regards.

ray-001 commented 5 years ago

Hi @juban,

Thanks for the reply and the solution. This will work for me.

Kind regards, Raymond