1. Я так понимаю тут отсутствие cache используется для определения первого шага в рекурсии, когда теги надо отсортировать. Так делать плохо. Необходимо выделить отдельную функцию, типа:
```
def self.get_hashes(tags)
  self.sort_tags(tags)
  self.calculate_hashes(tags, relavance: 0, cache: HashCache.new)
```

2. Мне не нравится функция с побочным эффектом sort_tags. Такой код был бы понятнее
```
  tags = self.sort_tags(tags)
```
Путанницу вносит совпадение имен локальной переменной и, как я понимаю поля в таблице

3. sort_tags - вообще кажется мне излишней. Строка `tags = self.convert_tags_string_to_sorted_array(tags)` тут была бы уместнее.