Nano Hash - криптовалюты, майнинг, программирование

Как реализовать кеш с двоичным массивом в качестве ключа и двоичными массивами в качестве значений в Java

У меня есть требование создать кеш Java, который содержит все города и аэропорты. Итак, если я запрашиваю кеш для местоположения, скажем, города, он должен вернуть все аэропорты в этом городе, и если я запрашиваю местоположение, которое является аэропортом, я должен вернуть этот аэропорт. Кроме того, каждое местоположение должно храниться в виде массива байтов в кеше (поскольку открытый интерфейс для запроса кеша имеет байт [] в качестве параметра для местоположения). Другие соображения:

  1. Поиск должен быть очень быстрым, максимально быстрым
  2. Кэш загружается только один раз при запуске системы. После загрузки он не меняется.
  3. Поскольку он загружается только один раз, мы можем отсортировать его, если это ускорит поиск.

Что у меня есть до сих пор:

Подход 1

Создайте тонкую обертку над массивом byte[], скажем, ByteWrapper. Поместите каждое местоположение (и аэропорты, и города) в качестве ключа на карту (TreeMap?). Используйте списки ByteWrapper (содержащие аэропорты, где это применимо) в качестве значений.

Подход 2

Создайте многомерный массив byte[], который отсортирован по местоположению. По сути это карта. Затем используйте бинарный поиск, чтобы найти ключ и вернуть результаты.

Какой подход вы бы предложили? Пожалуйста, дайте мне знать, если у вас есть идеи получше. Спасибо.

03.12.2009

  • Побалуйте меня: какого хрена вы используете byte[] для представления городов и аэропортов? 04.12.2009
  • :) Хм. У нас есть еще один кеш, который использует bytes[] (закодированные аэропорты) в качестве ключа для другой информации об аэропортах. Это сделано для экономии места и ускорения доступа. Проблема с этим кешем в том, что он основан на аэропортах. Мы хотим поддержать города сейчас. Однако мы не хотим создавать еще один уровень (Город-›аэропорт-›другая информация-›подробнее) в этом кеше, так как в нем уже есть 3-4 уровня. Итак, мы создаем этот новый кеш, который будет использоваться для получения аэропортов для данного города/аэропорта, и использовать результаты для запроса существующего кеша на основе аэропорта. Хм, я расплывчато? :) 04.12.2009
  • хм ни от кого нет ответов? я работаю над решением. сообщит вам результаты tomm. Пожалуйста, предложите несколько лучших идей, если у вас есть. 05.12.2009

Ответы:


1

Тот факт, что открытый API основан на byte[], не должен обязательно влиять на внутренние детали вашего кеша.

Второе наблюдение заключается в том, что это не проблема обобщенной структуры данных. И пространство всех аэропортов, и пространство всех городов конечно и хорошо известно. (Вы даже знаете размер).

Хэш-карты, деревья и т. д. — все это алгоритмы, гарантирующие определенные характеристики производительности в установленных пределах для общего использования.

Поскольку целостность данных не является проблемой («данные не изменяются») и если соображения пространства не критичны («как можно быстрее»), то почему бы и нет:

[Редактировать: этот фрагмент каким-то образом потерялся при вырезании и вставке: вы индексируете (нумеруете) свои города и аэропорты, учитывая, что вы знаете эти наборы, и они фактически статичны.]

// these need to get initialized on startup
// this initialization can be optimized.

Map<byte[], Long> airportIndexes = new HashMap<byte[], Long>(NUMBER_OF_AIRPORTS);
Map<byte[], Long> citiesIndexes = new HashMap<byte[], Long>(NUMBER_OF_CITIES);

Map<Long, byte[]> airports = new HashMap<Long, byte[]>(NUMBER_OF_AIRPORTS);
Map<Long, byte[]> cities = new HashMap<Long, byte[]>(NUMBER_OF_CITIES);

long[][] airportToCitiesMappings = new byte[NUMBER_OF_AIRPORTS][];
long[][] citiesToAirportMappings = new byte[NUMBER_OF_CITIES][];


public List<byte[]> getCitiesNearAirport(byte[] airportName) {
   Long[] cityIndexes = getCitiesByIdxNearAirport(airportName);
   List<byte[]> cities = new ArrayList<byte[]>(cityIndexes.length);
   for(Long cityIdx : cityIndexes) {
       cities.add(cities.get(cityIdx));
   }
   return cities;
}
public long[] getCitiesByIdxNearAirport(Long airportIdx) {
   return airportToCitiesMappings[airportIdx];
}
public long[] getCitiesNearAirport(byte[] airportName) {
   return getCitiesNearAirport(airportIndexes.get(airportName));
}
public long[] getCitiesNearAirport(Long airportIdx) {
   return airportToCitiesMappings[airportIdx];
}
// .. repeat above pattern for airports.

Это должно дать вам характеристики производительности O (1). Существует значительная избыточность с точки зрения пространства.

04.12.2009
  • Спасибо. Несколько проблем с подходом 1) Карта airportIndexes всегда будет возвращать null, поскольку hashMap не будет считать 2-байтовые массивы равными, если они имеют одинаковые значения. 2) Преобразования между Long и Long и т. д. Я думаю, что могу создать только 1 многомерный массив, который имеет города + аэропорты в качестве измерения 1. Нам все равно, является ли ввод аэропортом или городом... нам просто нужно вернуть соответствующее отображение. Таким образом, если входным параметром является город, верните все аэропорты в этом городе, а если входным параметром является аэропорт, просто верните этот аэропорт. В этом случае можно обойтись без раздельного поиска городов и аэропортов. Любые идеи? 04.12.2009

  • 2

    Вам не нужны массивы байтов, строки будут в порядке.

    Как часто вы будете добавлять элементы в этот кеш? Я предполагаю, что это совершенно статично, поскольку они не строят новые города или аэропорты каждый день.

    Итак, что вы можете сделать, так это использовать два MultiHashMaps, один для города, а другой для аэропортов. Оформить заказ Google Multimap http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Multimap.html

    Если вы случайно используете mySQL, вы можете использовать таблицу на основе Memory Storage Engine.

    Многие базы данных могут закрепить таблицу в памяти, определенно это может сделать Oracle, так что это еще один способ.

    03.12.2009
  • Спасибо за ответ. Как я уже сказал, я должен использовать байтовые массивы, так как именно так будет запрашиваться кеш. Интерфейс не может быть изменен. Да, я могу хранить его как строки, но это потребует накладных расходов на преобразование между строками и байтами. Нет, я не могу использовать БД из-за накладных расходов на производительность. 04.12.2009

  • 3

    Попробуйте приблизиться к 1, поскольку byte[] — это тип объекта, который вы можете использовать примерно так:

    Map<byte[], List<byte[]>> cache = ... 
    

    Это, вероятно, самый простой подход, вам просто нужно будет выбрать реализацию для вашей карты. Вероятно, вам следует использовать HashMap, потому что это самое простое...

    Как сказал gustavc, использование HashMap не сработает, поэтому вместо этого вы можете использовать TreeMap с заданным компаратором:

    Map<byte[], List<byte[]>> m = new TreeMap<byte[], List<byte[]>>(new Comparator<byte[]>() {
        public int compare(byte[] o1, byte[] o2) {
            int result = (o1.length < o2.length ? -1 : (o1.length == o2.length ? 0 : 1));
            int index = 0;
            while (result == 0 && index < o1.length) {
                result = (o1[index] < o2[index] ? -1 : (o1[index] == o2[index] ? 0 : 1));
                index++;
            }
            return result;
        }
    });
    
    04.12.2009
  • Хэш-коды массивов основаны на идентификаторе объекта массива, а не на содержимом массива. Следующее не сработает: byte[] a = {1}, b = {1}; map.put(a, someValue); assert map.get(b) == map.get(a); 04.12.2009

  • 4

    Итак, вот что я сделал до сих пор:

    private static byte[][][] cache = null; // this is the actual cache
    // this map has ByteArrayWrapper(a wrapper over byte[]) as key which
    //  can be an airport or city and index of corresponding 
    // airport/airports in byte[][][]cache as value
    Map<ByteArrayWrapper, Integer> byteLocationIndexes = null;
    /**
    * This is how cache is queried. You can pass an airport or city as a location parameter
    * It will fetch the corresponding airport/airports
    */
    private byte[][] getAllAirportsForLocation(ByteArrayWrapper location) {
        byte[][] airports = null;
        airports = byteLocationIndexes.get(location)== null ? null : cache[byteLocationIndexes.get(location).intValue()];
        return airports;
    }
    

    Я оценивал производительность, используя как String в качестве ключа в indexMap (и используя кэш String[][]), так и ByteArrayWrapper в качестве ключа (и byte[] в качестве кеша). Если я использую ByteArrayWrapper и byte[][][] cache, улучшение на 15-20%.

    Что еще можно сделать для повышения производительности? Поможет ли мне использовать другую реализацию Map? Поскольку кеш загружается только один раз и никогда не изменяется, его можно сортировать. Больше всего времени уходит на поиск ключа в byteLocationIndexes, и это узкое место. Я уже вычисляю hashCode во время создания объекта и сохраняю его как локальную переменную в ByteArrayWrapper.

    Какие-либо предложения?

    08.12.2009
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..