fergiemcdowall / search-index

A persistent, network resilient, full text search library for the browser and Node.js
MIT License
1.39k stars 149 forks source link

SORT option not work #541

Closed 1eeing closed 3 years ago

1eeing commented 3 years ago

DEMO as follows:

(async () => {
  const si = require('../../')
  const cars = [
    {
      _id: 0,
      make: 'Volvo',
      colour: 'Black',
      year: 2011,
      price: 82580,
      model: 'XC90',
      drivetrain: 'Hybrid'
    },
    {
      _id: 1,
      make: 'Tesla',
      colour: 'White',
      year: 2012,
      price: 36693,
      model: 'S',
      drivetrain: 'Electric'
    },
    {
      _id: 2,
      make: 'Volvo',
      colour: 'Blue',
      year: 2005,
      price: 36130,
      model: 'XC60',
      drivetrain: 'Hybrid'
    },
    {
      _id: 3,
      make: 'Volvo',
      colour: 'Black',
      year: 2016,
      price: 42522,
      model: 'XC90',
      drivetrain: 'Diesel'
    },
    {
      _id: 4,
      make: 'Volvo',
      colour: 'Red',
      year: 2010,
      price: 60084,
      model: 'XC60',
      drivetrain: 'Petrol'
    },
    {
      _id: 5,
      make: 'BMW',
      colour: 'Black',
      year: 2013,
      price: 88503,
      model: '3-series',
      drivetrain: 'Diesel'
    },
    {
      _id: 6,
      make: 'Volvo',
      colour: 'Silver',
      year: 2011,
      price: 73297,
      model: 'XC60',
      drivetrain: 'Petrol'
    },
    {
      _id: 7,
      make: 'Volvo',
      colour: 'Silver',
      year: 2009,
      price: 55938,
      model: 'XC90',
      drivetrain: 'Petrol'
    },
    {
      _id: 8,
      make: 'Volvo',
      colour: 'Silver',
      year: 2010,
      price: 92375,
      model: 'XC60',
      drivetrain: 'Petrol'
    },
    {
      _id: 9,
      make: 'Tesla',
      colour: 'Red',
      year: 2008,
      price: 74017,
      model: 'X',
      drivetrain: 'Electric'
    },
    {
      _id: 10,
      make: 'Tesla',
      colour: 'Red',
      year: 2008,
      price: 74017,
      model: 'X',
      drivetrain: 'Diesel-2'
    }
  ]

  const print = txt => console.log(JSON.stringify(txt, null, 2))
  const db = await si({ name: 'QUERY' })

  await db.PUT(cars)

  console.log('\nSEARCH and SORT ->')
  await db.QUERY({
    SEARCH: ['make:Volvo', 'drivetrain:Petrol']
  }, {
    SORT: {
      TYPE: 'NUMERIC',
      DIRECTION: 'DESCENDING',
      FIELD: 'price',
    },
  }).then(print)
})()

When I did not pass in SORT, the result is as follows:

SEARCH and SORT ->
{
  "RESULT": [
    {
      "_id": "4",
      "_match": [
        "make:volvo#1.00",
        "drivetrain:petrol#1.00"
      ],
      "_score": 2.2
    },
    {
      "_id": "6",
      "_match": [
        "make:volvo#1.00",
        "drivetrain:petrol#1.00"
      ],
      "_score": 2.2
    },
    {
      "_id": "7",
      "_match": [
        "make:volvo#1.00",
        "drivetrain:petrol#1.00"
      ],
      "_score": 2.2
    },
    {
      "_id": "8",
      "_match": [
        "make:volvo#1.00",
        "drivetrain:petrol#1.00"
      ],
      "_score": 2.2
    }
  ],
  "RESULT_LENGTH": 4
}

But when I pass in, the result is still the same:

SEARCH and SORT ->
{
  "RESULT": [
    {
      "_id": "4",
      "_match": [
        "make:volvo#1.00",
        "drivetrain:petrol#1.00"
      ],
      "_score": 2.2
    },
    {
      "_id": "6",
      "_match": [
        "make:volvo#1.00",
        "drivetrain:petrol#1.00"
      ],
      "_score": 2.2
    },
    {
      "_id": "7",
      "_match": [
        "make:volvo#1.00",
        "drivetrain:petrol#1.00"
      ],
      "_score": 2.2
    },
    {
      "_id": "8",
      "_match": [
        "make:volvo#1.00",
        "drivetrain:petrol#1.00"
      ],
      "_score": 2.2
    }
  ],
  "RESULT_LENGTH": 4
}

I don't know what to do. Please help.

fergiemcdowall commented 3 years ago

SORT sorts RESULT first by _score and then by _id. In the example above all each item in RESULT has the same _score value of 2.2, so sorting will have no effect.

What do you want to sort by?

1eeing commented 3 years ago

SORT sorts RESULT first by _score and then by _id. In the example above all each item in RESULT has the same _score value of 2.2, so sorting will have no effect.

What do you want to sort by?

I want to sort by price, but I don't know how to do it. Could you please give me an example?

fergiemcdowall commented 3 years ago

Something like this maybe? ->

QUERY({
  SEARCH: [{
    FIELD: 'price'
  }]
}, {
  SORT: {
    TYPE: 'NUMERIC',
    DIRECTION: 'DESCENDING',
    FIELD: '_match.price'
  }
}
fergiemcdowall commented 3 years ago

Or, to use your original query ->

db.QUERY({
  SEARCH: ['make:Volvo', 'drivetrain:Petrol', { FIELD: 'price' }]   // <- search for price
}, {
  SORT: {
    TYPE: 'NUMERIC',
    DIRECTION: 'DESCENDING',
    FIELD: '_match.price',     // <- prefix 'price' with '_match.'
  },
})

EDIT- added { FIELD: 'price' } to QUERY

1eeing commented 3 years ago

OK, I used a combination of the two to solve the problem. Because I found that if there is no price in the SEARCH, then there is no price in the results, and it cannot be sorted correctly. Thank you.

fergiemcdowall commented 3 years ago

Yes- its not totally intuitive- this is probably something that could be explained better in the docs

robgietema commented 2 years ago

@fergiemcdowall It seems the above API has changed and the docs are not updated. Reading the tests it seems you can now only sort based on what you specified in SCORE, is that correct?

fergiemcdowall commented 2 years ago

Yes, the API for SORT was updated in version 3, and it pretty much works as you say @robgietema

I have just updated the docs to make them a bit clearer. They weren't wrong as far as I can see, but they needed some clarification- SORT defaults to the contents of _score in every result, and SCORE.FIELD will only work if it is present in _match in every result.