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

Guide on pagination #561

Closed
bidoubiwa opened this issue Oct 19, 2020 · 4 comments · Fixed by #1753
Closed

Guide on pagination #561

bidoubiwa opened this issue Oct 19, 2020 · 4 comments · Fixed by #1753
Assignees
Milestone

Comments

@bidoubiwa
Copy link
Contributor

bidoubiwa commented Oct 19, 2020

Pagination best practice

MeiliSearch was not made for pagination. The idea is that you never have to "go to page 2".
In case you still want pagination, let us consider two pagination styles.

1. Infinity scroll, or arrow pagination: recommended

This pagination is recognizable by its absence of a numbered paginated page. It will either have no visual clues and will be done in the background while you scroll down infinitely (i.e.: dev.to) or using arrows that let you navigate to the next page of results.

Pagination

To achieve this pagination you should make searches based on two pieces of information.

  1. How much result do you want to have on a single page (or add on one scroll)
  2. Are there anymore hits after this batch?

Showing a certain amount of hits per batch can be done using the limit. But since you don't want to give the possibility to your user to click on the right arrow if there are no more hits, you need to know where to stop. We suggest to always add + 1 on your limit count, if the number of results MeiliSearch returns is lower than this number, you should inform the user that he arrived at the end the results (by graying out the arrow for example).

For this example, let's say that we want 100 hits per page. Pagination will work like this. We will be using two search parameter to achieve pagination: limit and offset

  • Make a first search on batman with limit: 101 and offset: 0.
    • As we receive 101 results we know that there are more results.
    • We show 100 hits
    • We add a right arrow at the bottom
  • The user scrolls to the end of the page or clicks on the right arrow
  • Trigger another search on batman with limit: 101 and offset: 100
    • As we receive 101 results we know that there are more results.
    • We show 100 hits
    • We add a right arrow at the bottom
  • The user scrolls to the end of the page or clicks on the right arrow
  • Trigger another search on batman with limit: 100 and offset: 200
    • As we receive only 10 results we know that there are NO more possible results.
    • We show 100 hits
    • We grey out a right arrow at the bottom
  • The users can not click on the right arrow

As you may observe, the only parameter changing between each pagination is the offset.

⚠️ ❗️As it is possible to go infinite. We strongly suggest stopping around 1000 hits. Because the bigger the offset the longer it takes MeiliSearch to return the next results. This can be done by putting a limit on the offset value. This performance issue is due to the fact that MeiliSearch needs to sort limit + offset documents before returning the results. Thus instead of stoping the sort at 20 documents, it would have to stop the sort at 220 documents. Which takes more time.

2. Numbered Pagination or Finished Pagination: NOT recommended

this is NOT recommended

Finished pagination is the most known pagination system:
Screenshot 2020-10-20 at 13 50 59

While it has its uses, it is not a style that fits well with MeiliSearch.

No exact knowledge of the nb of hits

Meilisearch search response info nbHits is most of the time an upper bound approximation of the numbers of hits. It is not a reliable information unless the other search response info exhaustiveNbHits is true.

Perfomances issues

Another problem comes from performance issues when paginating to lets say page 200. Since we are using a bucket sort, having the first 20 results is way faster than having the 2000th result.
So giving the possibility to a user to directly jump to page 200 is not a good experience.

Because of this behavior we do not recommend a finished pagination.

How to make a numbered pagination with limited damage

If you want to create finished pagination you need to set a limit of results during your search. MeiliSearch is designed to fastly retrieve the best matching documents (the 20 firsts in a basic search request) but not to return the exact and exhaustive number of documents matching your request, for performance reasons.

What you concretely have to do is to set the limit search parameter to 1000.

MeiliSearch will return a hits array (less or equals to 1000) and the length of thishits array is the number of results -> you can now know the number of pages.
Depending on which page you want to display, you just have to take the piece of hits you need to display the expected results.

Example:
I have a front end application with finished pagination and I want to display 10 results per page.
I search for prince with limit set to 1000.
I get 32 results in hits.

  • I know that I have 22 / 10 = 2,2 => 3 pages to display
  • I will display the hits from 0 to 9 for page 1, 10 to 19 for page 2, and 20 to 22 for the last page.

💡As this technique lowers the performance of the search **we recommend setting the limit of results to a maximum of 1000 **. If you want to improve your performance, you can choose a lower limit. Algolia also sets the limit to 1000 for their pagination by default (see this page of docs).

Todo

Creation of a guide

A (small) guide should be made explaining how to create a pagination system with MeiliSearch.

This guide will be added in the search main concept guide as an example of what can be done using the search route.

The guide should only use curl and MeiliSearch routes. No other external library. Once it is written with cURL our other clients (ruby, js, php,..) will be able to add code-samples to match the cURL examples and thus the guide will be available in all languages.

Like this:
Screenshot 2020-10-19 at 20 57 09

To showcase the pagination, use both limit and offset but without using nbHits as it is not a reliable source of information. It should explain to the user how to paginate with arrows :

example:
Pagination

For example, if every page should have 20 results, using the search routes it should look like this:

  • Search on q = "batman", limit = 20, offset = 0
  • Hit the arrow
  • Search on q = "batman", limit = 20, offset = 20
  • Hit the right arrow
  • Search on q = "batman", limit = 20, offset = 40
    ...

The guide should mention the numbered pagination and explain that it is not recommended.

@curquiza curquiza pinned this issue Oct 20, 2020
@curquiza
Copy link
Member

curquiza commented Oct 20, 2020

How to make a numbered pagination with limited damage

If you still want to create a numbered pagination system, we suggest you hard set the limit to 1000 results.
@curquiza could you confirm how to do this pagination system?

If you want to create a finished pagination you indeed need to set a limit of results during your search. MeiliSearch is designed to fastly retrieve the best matching documents (the 20 firsts in a basic search request) but not to return the exact and exhaustif number of documents matching your request, for performance reasons.

What you concretely have to do is to set the limitsearch parameter to 1000.

MeiliSearch will return a hits array (less or equals to 1000) and the length of thishits array is the number of results -> you can now know the number of pages.
Depending on which page you want to display, you just have to take the piece of hits you need to display the expected results.

Example:
I have a front end application with a finished pagination and I want to display 10 results per page.
I search for prince with limit set to 1000.
I get 32 results in hits.

  • I know that I have 22 / 10 = 2,2 => 3 pages to display
  • I will display the hits from 0 to 9 for page 1, 10 to 19 for page 2, and 20 to 22 for the last page.

💡 Algolia sets the limit to 1000 for their pagination by default (see this page of docs), that's why we also recommend using 1000 as a limitation, but if you want to improve your performance, you can choose a lower limit.

@dichotommy dichotommy unpinned this issue Jan 26, 2021
bors bot added a commit to meilisearch/meilisearch-laravel-scout that referenced this issue Jan 27, 2021
80: Fix getTotalCount() method r=curquiza a=curquiza

Remove `nbHits` usage because this is not reliable information.

The Meili team is aware of this. Here are the different issues and comments about it to explain why it's confusing, and why we should not use it:
- meilisearch/meilisearch#1120
- meilisearch/documentation#561
- meilisearch/meilisearch-php#119 (comment)

TLDR;
`nbHits` is not reliable for pagination because can be exhaustive or not, depending on the value of `exhaustiveNbHits` that MeiliSearch returns which is always `false` for the moment.

We are sorry for this. We all hope this confusion will be fixed asap in MeiliSearch.

⚠️ The linter error in the CI will be fixed with #82  

Co-authored-by: Clémentine Urquizar <[email protected]>
@dichotommy dichotommy removed their assignment Nov 10, 2021
@dichotommy
Copy link
Contributor

@bidoubiwa and @gmourier created a rough draft(private link) of the pagination guide that @guimachiavelli will edit for release alongside v0.28 docs.

@guimachiavelli guimachiavelli linked a pull request Jun 23, 2022 that will close this issue
bors bot added a commit that referenced this issue Jul 7, 2022
1753: v0.28: Pagination guide r=guimachiavelli a=guimachiavelli

Closes #561

Co-authored-by: gui machiavelli <[email protected]>
Co-authored-by: gui machiavelli <[email protected]>
bors bot added a commit that referenced this issue Jul 11, 2022
1707: v0.28 r=guimachiavelli a=guimachiavelli

This is a staging PR for all changes related to Meilisearch v0.28.

Please avoid making changes directly to this PR; instead, create new child branches based off this one.

Closes #1687, #1688, #1691, #1692, #1693, #1694, #1699, #1700, #1701, #1702, #1703, #1704, #1706, #1722, #1727, #561

Co-authored-by: gui machiavelli <[email protected]>
Co-authored-by: gui machiavelli <[email protected]>
Co-authored-by: Tommy Melvin <[email protected]>
Co-authored-by: Maryam Sulemani <[email protected]>
Co-authored-by: Maryam <[email protected]>
@guimachiavelli
Copy link
Member

For those interested, the docs now have a dedicated guide explaining how to handle pagination in Meilisearch.

@guimachiavelli guimachiavelli unpinned this issue Jul 18, 2022
@ManyTheFish
Copy link
Member

ManyTheFish commented Jul 27, 2022

Hello!
For those interested, we are working on improving pagination in Meilisearch and we just released a first prototype that makes creating numbered pagination way easier! 🔥
It would be super helpful if you could let us know if this helps with your issue.
To know more about the prototype and how to use it, take a look at the dedicated discussion.

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

Successfully merging a pull request may close this issue.

5 participants