lucaong / minisearch

Tiny and powerful JavaScript full-text search engine for browser and Node
https://lucaong.github.io/minisearch/
MIT License
4.9k stars 137 forks source link

Question: Custom sort within search results #87

Closed florianmatz closed 3 years ago

florianmatz commented 3 years ago

Hi Luca,

as promised - another issue / question:

Again, kind of refering to categories.

Say, you filter the search results by category:

"kategorien": ["zuletztGeoeffnet", "favoriten"];

The search results are - by default and absolutely reasonably - sorted by score.

But now, as for example for all elements with the category "zuletztGeoffnet" -> recently opened stuff, I want to apply a custom sorting (say by a simple index that is within the data):

 ...
  "kategorien": ["zuletztGeoeffnet", "favoriten"],
  "zuletztGeoffnetIndex": 2,
 },
{
 ...
  "kategorien": ["zuletztGeoeffnet", "favoriten"],
  "zuletztGeoffnetIndex": 0,
 }

I want the results to be sorted by index. Is this something that might of interest for MiniSearch or kind of implemented and I just didn't get it?

Or, in your opinion in the developers responsibility?

And I have a little side question that I'm sneaking in here: Do you recommend to clear the index or to do something else to free up memory space after unmounting a component (React) utilizing MiniSearch (or better said, the hook)

lucaong commented 3 years ago

Hi @florianmatz , good question, I hope my answer can clarify that.

As you say, the custom sorting is something that can be rather easily implemented in user code:

const miniSearch = new MiniSearch({
  fields: [/* ... */],
  storeFields: ['kategorien', 'zuletztGeoffnetIndex']
})

miniSearch.addAll(documents)

miniSearch.search('some query', {
  filter: (result) => result.kategorien.includes('favoriten')
}).sort(({ zuletztGeoffnetIndex: a }, { zuletztGeoffnetIndex: b }) => a > b ? 1 : -1)

That said, I will think about adding custom sorting as a feature in MiniSearch. On one hand, it is already possible to implement it easily in user code, so it does not sound like a core feature. On the other hand, implementing it as an option could make it possible to skip the default sorting by relevance, improving performance on large result sets.

As for your second question, if the MiniSearch instance is only a local reference of the component, it should be already cleaned up by the garbage collector as soon as your component is dismissed and the index is not reachable anymore. If instead you keep the MiniSearch instance in some global context, it could make sense to clear it: ultimately it is a trade off between memory utilization and performance. If the chance that you will be reusing the index are high, it might make sense to keep it "hot", otherwise better to clear it up.

I normally save the MiniSearch instance as a local field or component state (or use react-minisearch, which does essentially the same) so I don't need to care about cleaning it up manually.

florianmatz commented 3 years ago

Hi Luca,

perfect answers for both of my questions.

I've implemented the sorting exactly as in your suggestion.

I only have to figure out how to implement different sortings for different categories now, but that is on my side^^ It's a component Called "Filterable" which is basically used across all our searchable / filterable datasets. It can be used with differents UIs to switch categories, list virtualization, paging etc...

And now it is equipped with MiniSearch at the core.

Thank you :)