olivernn / lunr.js

A bit like Solr, but much smaller and not as bright
http://lunrjs.com
MIT License
8.96k stars 548 forks source link

Fix vector magnitude caching #142

Closed richardpoole closed 9 years ago

richardpoole commented 9 years ago

A typo in Vector.magnitude() was preventing it from returning the cached value

benpickles commented 9 years ago

Fancy adding a test to prevent this from happening again?

richardpoole commented 9 years ago

Not sure how I'd write a test for this since the method returns the correct value. I guess you could compare execution time between the first and subsequent calls, but that seems fragile.

benpickles commented 9 years ago

I guess that its output isn't covered by any of the existing tests is the problem.

richardpoole commented 9 years ago

I think it's covered here: https://github.com/olivernn/lunr.js/blob/master/test/vector_test.js#L3

benpickles commented 9 years ago

Ah yes, but not the caching. Oh well! I'll go back to sleep now :sleeping:

satchmorun commented 9 years ago

I saw that yesterday as well, but also noticed another thing: The insert method doesn't invalidate the cache when it adds new Nodes.

Maybe that's ok, since Vectors seem to be mostly one-use, but in cases where they might not be, the typo actually prevents stale cache issues.

richardpoole commented 9 years ago

Thanks @satchmorun. I've added cache invalidation to Vector.insert() and a corresponding test.

olivernn commented 9 years ago

Tpying is hrd! Good spot, wish there was a better way to prevent my fat fingered mashing of the keyboard resulting in bugs like this, any ideas?

https://www.youtube.com/watch?v=OqjF7HKSaaI

I've released version 0.5.8 with this change in, let me know if there are any issues, and thanks again for the pr.

richardpoole commented 9 years ago

Haha, easily done. Caching code isn't exactly easy to test. :)

We could try something like this (not tested):

var cached = function (key, func) {
  return function () {
    if (this[key]) return this[key]
    return this[key] = func.apply(this, arguments);
  }
}

lunr.Vector.prototype.magnitude = cached('_magnitude', function () {
  var node = this.list,
      sumOfSquares = 0,
      val

  while (node) {
    val = node.val
    sumOfSquares += val * val
    node = node.next
  }

  return Math.sqrt(sumOfSquares)
})

However it doesn't prevent typos in the invalidation code (e.g. this._magniture = undefined) and it makes the code harder to read. Personally, I think the risk of a typo in the caching code is the lesser of two evils.