Приходилось ли реализовывать индексирование данных в структурах Go для поиска по ключу
Что проверяют
Знаете ли вы, как устроена встроенная хеш-таблица и где она перестаёт подходить. Вопрос звучит бытово, но за ним идут уточнения про сравнимые ключи, изменение значений на месте и одновременный доступ.
Как отвечать
Начните с основного инструмента: map даёт доступ по ключу за амортизированное постоянное время, а ключ обязан быть сравнимым, поэтому срез, карта и функция ключом быть не могут, а структура из сравнимых полей может.
type Key struct {
Tenant string
SKU string
}
index := make(map[Key]*Item, len(items))
for i := range items {
index[Key{items[i].Tenant, items[i].SKU}] = &items[i]
}В примере важны две детали: составной ключ структурой вместо склейки строк через разделитель и указатель в значении, чтобы не копировать запись и иметь возможность её менять.
Дальше про вторичные индексы вида map[string][]*Item для поиска по неуникальному полю и про случаи, когда карта не подходит. Диапазон, сортированный обход, поиск ближайшего это отсортированный срез плюс двоичный поиск или дерево. Для большого статичного набора срез с картой смещений экономит память и щадит сборщик мусора. Размер карты стоит задавать заранее, чтобы не платить за перестроения.
Про одновременный доступ скажите сами: встроенная карта не защищена, обычный путь это мьютекс на чтение и запись, а sync.Map оправдан при редких записях и непересекающихся ключах.
Где спотыкаются
Пробуют менять значение на месте. Взять адрес элемента карты нельзя, присвоение полю структуры, лежащей в карте значением, не компилируется. Кандидат достаёт копию, правит её и удивляется, что индекс не изменился.
Полагаются на порядок обхода. Он намеренно случайный, и тест, сравнивающий собранную из карты строку с эталоном, будет падать через раз. Для стабильного вывода ключи собирают в срез и сортируют.
Читают карту из нескольких горутин одновременно с записью. Это не редкая гонка, а аварийное завершение по встроенной проверке, и проявляется оно под нагрузкой. Рядом: индекс, в который только добавляют и никогда не чистят, тихо растёт всю жизнь процесса.