4 ms·
I think the real question is: why not use trigrams of bytes (from the UTF8 representation) instead of Unicode codepoints? Seems like that would simplify everyth
by roca 5y ago
I think the real question is: why not use trigrams of bytes (from the UTF8 representation) instead of Unicode codepoints? Seems like that would simplify everything.
If they have data showing that doesn't work as well in practice, I'd love to know what it is, because I can't think of a reason off the top of my head why it wouldn't work well. Obviously it could only be worse in non-ASCII situations, which are already super-rare.
- bastawhiz 5y agoBecause then you've potentially got a lot of trigrams for 4-byte Unicode characters that only contain the first three bytes of the character. Even if they're rare, you're effectively hamstringing anyone who uses a language that includes four byte characters or emoji. And for languages that use characters with three bytes, you're essentially indexing individual characters. Even in the case where you're using two byte characters, which is very common, your trigrams become one and a half characters. But moreover, the prefix of many of your trigrams is just going to be surrogate pair bytes. At this point, the whole point of building a reverse index is somewhat moot if you're indexing over parts of characters, byte sequences that are not useful on their own, and other such garbage. Yes, the ASCII happy path is fine, but you've essentially eliminated Unicode support entirely.
- roca 5y ago> the prefix of many of your trigrams is just going to be surrogate pair bytes I'm not sure what you mean by this. Surrogate pairs are a UTF16 thing, not relevant here. > you've essentially eliminated Unicode support entirely. That's not obvious to me at all. In text containing non-ASCII characters, the trigrams that span UTF8 character boundaries are likely to give you the selectivity you need. > And for languages that use characters with three bytes, you're essentially indexing individual characters Not at all. The index would be a function of character pairs. It certainly could be worse but how much worse would depend on the characteristics of the source texts, which is why I think it would be really interesting to see whatever data Sourcegraph has on this.
- bastawhiz 5y ago> Not at all. The index would be a function of character pairs. If it's a three byte trigram and it covers a three byte character, please explain how it could be anything other than a trigram containing a single character? If you want to cover a pair characters, you need six bytes. Which is also simply worse than the 42 bits you need to encode two Unicode code points as integers (as the author is doing now).
- roca 5y agoBecause there are trigrams crossing the boundaries between characters. E.g. given the bytes ABCXYZ, the trigrams are not just ABC and XYZ but also BCX and CXY. Then the question is, assuming ABC, XYZ, BCX and CXY are all present in a document, what is the probability that ABCXYZ is present in the document? If it's close to 1, then the byte trigram index is about as powerful as a character bigram index. Of course it's also true that bigrams might be inadequately selective, but the underlying alphabet is probably larger than ASCII if it encodes to 3 bytes in UTF8. Again I'm not arguing that trigrams-over-bytes is necessarily the best option here, just that it's simpler and a decision to do trigrams over Unicode characters needs data to justify it, and I'd love to know what that data is.
- Scaevolus 5y agoTrigrams have an approximately 30% false positive rate when used as a filter for whether to skip repos.
- roca 5y agoThat's interesting, and doesn't surprise me. When I wrote an n-gram full-text search for email 20 years ago, I used 4-grams to get the required selectivity. I imagine code could be worse because of more restricted syntax and alphabet. However, this doesn't bear directly on the question of trigrams-over-UTF8-bytes vs trigrams-over-Unicode-chars.
- tialaramex 5y ago> Even if they're rare, you're effectively hamstringing anyone who uses a language that includes four byte characters or emoji. I don't think so. Suppose I am looking for some code that I remember has a comment with the shark emoji U+1F988 in double quotes. So the trigrams this backend is searching for are 0x22F09F and 0xA68822. The first trigram is only going to appear in documents quoting an emoji animal. Yes it will match kangaroos or indeed crabs in a few Rust crates, but it will entirely skip every program that doesn't have an emoji animal in quotes. The second trigram only matches documents with certain 3 or 4-byte Unicode scalars (such as an emoji) at the end of a quote. It will not, for example, match most of those Rust documents talking about crabs since crabs do not end with the bytes 0xA6 0x88. So chances are you went from "Oh no, a 4 byte character, surely the worst case" to only the documents you actually wanted before the main algorithm even began running. > But moreover, the prefix of many of your trigrams is just going to be surrogate pair bytes. I assume this is just a brain misfiring, this is obviously not how UTF-8 works.
- bastawhiz 5y agoThat works great for emojis and terribly for Japanese, Chinese, Korean, Thai, etc. where each character is a three byte codepoint. Then you're literally just building a reverse index of individual characters. If this was effective, they wouldn't be using trigrams in the first place: it's a much simpler system to implement. Sure, most languages use Latin characters in keywords, but that's unhelpful for comments.
- Sesse__ 5y agoIt's entirely possible to do so, and I do it in plocate, which solves a similar problem in pretty much the same way. But it's non-ideal for case-insensitive matching (see previous comment).