milli icon indicating copy to clipboard operation
milli copied to clipboard

Word prefix pair proximity docids indexation refactor

Open loiclec opened this issue 3 years ago • 0 comments

Pull Request

What does this PR do?

Refactor the code of WordPrefixPairProximityDocIds to make it much faster, fix a bug, and add a unit test.

Why is it faster?

Because we avoid using a sorter to insert the (word1, prefix, proximity) keys and their associated bitmaps, and thus we don't have to sort a potentially very big set of data. I have also added a couple of other optimisations:

  1. reusing allocations
  2. using a prefix trie instead of an array of prefixes to get all the prefixes of a word
  3. inserting directly into the database instead of putting the data in an intermediary grenad when possible. Also avoid checking for pre-existing values in the database when we know for certain that they do not exist.

What bug was fixed?

When reindexing, the new_prefix_fst_words prefixes may look like:

["ant",  "axo", "bor"]

which we group by first letter:

[["ant", "axo"], ["bor"]]

Later in the code, if we have the word2 "axolotl", we try to find which subarray of prefixes contains its prefixes. This check is done with word2.starts_with(subarray_prefixes[0]), but "axolotl".starts_with("ant") is false, and thus we wrongly think that there are no prefixes in new_prefix_fst_words that are prefixes of axolotl.

StrStrU8Codec

I had to change the encoding of StrStrU8Codec to make the second string null-terminated as well. I don't think this should be a problem, but I may have missed some nuances about the impacts of this change.

Requests when reviewing this PR

I have explained what the code does in the module documentation of word_pair_proximity_prefix_docids. It would be nice if someone could read it and give their opinion on whether it is a clear explanation or not.

I also have a couple questions regarding the code itself:

  • Should we clean up and factor out the PrefixTrieNode code to try and make broader use of it outside this module? For now, the prefixes undergo a few transformations: from FST, to array, to prefix trie. It seems like it could be simplified.
  • I wrote a function called write_into_lmdb_database_without_merging. (1) Are we okay with such a function existing? (2) Should it be in grenad_helpers instead?

Benchmark Results

We reduce the time it takes to index about 8% in most cases, but it varies between -3% and -20%.

group                                                                     indexing_main_ce90fc62                  indexing_word-prefix-pair-proximity-docids-refactor_cbad2023
-----                                                                     ----------------------                  ------------------------------------------------------------
indexing/-geo-delete-facetedNumber-facetedGeo-searchable-                 1.00  1893.0±233.03µs        ? ?/sec    1.01  1921.2±260.79µs        ? ?/sec
indexing/-movies-delete-facetedString-facetedNumber-searchable-           1.05      9.4±3.51ms        ? ?/sec     1.00      9.0±2.14ms        ? ?/sec
indexing/-movies-delete-facetedString-facetedNumber-searchable-nested-    1.22    18.3±11.42ms        ? ?/sec     1.00     15.0±5.79ms        ? ?/sec
indexing/-songs-delete-facetedString-facetedNumber-searchable-            1.00     41.4±4.20ms        ? ?/sec     1.28    53.0±13.97ms        ? ?/sec
indexing/-wiki-delete-searchable-                                         1.00   285.6±18.12ms        ? ?/sec     1.03   293.1±16.09ms        ? ?/sec
indexing/Indexing geo_point                                               1.03      60.8±0.45s        ? ?/sec     1.00      58.8±0.68s        ? ?/sec
indexing/Indexing movies in three batches                                 1.14      16.5±0.30s        ? ?/sec     1.00      14.5±0.24s        ? ?/sec
indexing/Indexing movies with default settings                            1.11      13.7±0.07s        ? ?/sec     1.00      12.3±0.28s        ? ?/sec
indexing/Indexing nested movies with default settings                     1.10      10.6±0.11s        ? ?/sec     1.00       9.6±0.15s        ? ?/sec
indexing/Indexing nested movies without any facets                        1.11       9.4±0.15s        ? ?/sec     1.00       8.5±0.10s        ? ?/sec
indexing/Indexing songs in three batches with default settings            1.18      66.2±0.39s        ? ?/sec     1.00      56.0±0.67s        ? ?/sec
indexing/Indexing songs with default settings                             1.07      58.7±1.26s        ? ?/sec     1.00      54.7±1.71s        ? ?/sec
indexing/Indexing songs without any facets                                1.08      53.1±0.88s        ? ?/sec     1.00      49.3±1.43s        ? ?/sec
indexing/Indexing songs without faceted numbers                           1.08      57.7±1.33s        ? ?/sec     1.00      53.3±0.98s        ? ?/sec
indexing/Indexing wiki                                                    1.06   1051.1±21.46s        ? ?/sec     1.00    989.6±24.55s        ? ?/sec
indexing/Indexing wiki in three batches                                   1.20    1184.8±8.93s        ? ?/sec     1.00     989.7±7.06s        ? ?/sec
indexing/Reindexing geo_point                                             1.04      67.5±0.75s        ? ?/sec     1.00      64.9±0.32s        ? ?/sec
indexing/Reindexing movies with default settings                          1.12      13.9±0.17s        ? ?/sec     1.00      12.4±0.13s        ? ?/sec
indexing/Reindexing songs with default settings                           1.05      60.6±0.84s        ? ?/sec     1.00      57.5±0.99s        ? ?/sec
indexing/Reindexing wiki                                                  1.07   1725.0±17.92s        ? ?/sec     1.00    1611.4±9.90s        ? ?/sec

loiclec avatar Jul 14 '22 11:07 loiclec