iPhone жесткие вычисления и кеширование - PullRequest
2 голосов
/ 04 декабря 2009

У меня проблема. У меня есть база данных с 500k записями. Каждая запись хранит широту, долготу, вид животного, дату наблюдения. Я должен нарисовать сетку (15x10) над представлением mapkit, которая показывает концентрацию вида в этой ячейке сетки. Каждая ячейка имеет размер 32х32.

Если я вычисляю во время выполнения, это очень медленно . Кто-нибудь знает, как его кэшировать? В памяти или в базе данных.

Структура данных:

Замечание:

  • Широта
  • Долгота
  • Дата
  • Specie
  • некоторые другие неважные данные

Образец экрана:

альтернативный текст http://img6.imageshack.us/img6/7562/20091204201332.png

В каждой красной пометке указано количество видов в этом регионе.

Код, который я сейчас использую: данные -> выбрать из базы данных, это все наблюдения в области карты

for (int row = 0; row < rows; row++)
 { 
  for (int column = 0; column < columns; column++)
  {
   speciesPerBox=0;
   minG=boxes[row][column].longitude;
   if (column!=columns-1) {
    maxG=boxes[row][column+1].longitude;
   } else {
    maxG=buttomRight.longitude;
   }

   maxL=boxes[row][column].latitude;
   if (row!=rows-1) {
    minL=boxes[row+1][column].latitude;
   } else {
    minL=buttomRight.latitude;
   }

   for (int i=0; i<sightingCount; i++) {
    l=data[i].latitude;
    g=data[i].longitude;

    if (l>=minL&&l<maxL&&g>=minG&&g<maxG) {
     for (int j=0; j<speciesPerBox; j++) {
       if (speciesCountArray[j]==data[i].specie) {
        hasSpecie=YES;
       }
      }

      if (hasSpecie==NO) {
       speciesCountArray[speciesPerBox]=data[i].specie;
       speciesPerBox++;
      }

      hasSpecie=NO;


     }
    }
   }


   mapData[row][column].count = speciesPerBox;
  }
 }

Ответы [ 3 ]

4 голосов
/ 04 декабря 2009

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

Поскольку у вас есть 15 х 10 = 150 ячеек, вы получите 150 * [количество видов] записей в базе данных, что должно быть намного меньше.

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

1 голос
/ 04 декабря 2009

С 500k записями это звучит как работа с основными данными. Желательно основные данные на рабочем столе. Если данные не обновляются в реальном времени , вам следует обработать данные на более тяжелом оборудовании и просто использовать iPhone для их отображения. Это значительно упростит приложение, потому что вы просто сохраните значение для каждой ячейки карты.

Даже если вы хотите обработать его на iPhone, приложение должно обработать данные один раз и сохранить результаты. Похоже, нет никаких причин, чтобы приложение пересчитывало значение вида каждой ячейки карты каждый раз, когда оно хочет отобразить ячейку.

Я бы предложил создать объект в основных данных для представления наблюдений. Затем другой объект для представления географических квадратов. Установите связь между квадратами и наблюдениями, которые попадают в квадрат. Затем создайте расчетную стоимость вида в квадратной сущности. Тогда вам придется только пересчитать значение вида, если одно из наблюдений изменилось.

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

Edit01:

Подход к проблеме с совершенно другого ракурса. В основных данных.

(1) Создайте граф объектов записей наблюдений таким образом, чтобы каждый объект наблюдения имел обратную связь с другими объектами наблюдения, которые ближе всего к нему географически. Это создаст граф объектов, который будет выглядеть как плоская нерегулярная сеть.

(2) Создать методы для класса наблюденияRecords, которые (а) определяют, лежит ли запись в границах произвольного географического квадрата (б), спрашивают, возвращают ли каждая из ее освобожденных записей, если они также находятся в квадрате (в) его собственный вид видов и количество всех связанных записей.

(3) Разделите вашу карту на несколько разумных квадратиков, например одна секунда квадрата дуги. В этом квадрате выберите одну связанную запись и добавьте ее в список. Выберите некоторый процент всех записей, например, 1 на каждые 100 или 1000, чтобы сократить список с 500 тыс. До, чтобы создать подсписок, который можно быстро найти с помощью предиката грубой силы. Давайте назовем эти записи в списке флагами сетки.

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

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

Это займет некоторое усилие и время для настройки, но как только вы это сделаете, это будет довольно эффективно, особенно при увеличении. Для верхнего уровня просто подготовьте статическую карту с предварительно обработанной обработкой.

Надеюсь, я объяснил это достаточно хорошо. Трудно передать устно.

1 голос
/ 04 декабря 2009

Цикл for (int i=0; i<sightingCount; i++) убивает вашу производительность. Особенно большое количество if (l>=minL&&l<maxL&&g>=minG&&g<maxG) операторов, где будет пропущено большинство наблюдений.

Насколько велика sightingCount?

Сначала Вы должны использовать вид Пространственная оптимизация , например. простой: хранить списки количества видов на ячейку (назовем их «зонами»). Определите эти зоны достаточно большими, чтобы не тратить пространство. Но меньшие зоны обеспечивают лучшую производительность, а слишком малые зоны полностью изменяют эффект. Итак, сделайте его настраиваемым и протестируйте зоны разных размеров, чтобы найти хороший компромисс!

Когда пора суммировать количество видов в ячейке для рендеринга, определите, какие зоны в данной ячейке перекрываются (довольно простой и быстрый тест «наложение прямоугольника»). Тогда вам нужно только проверить количество видов этих зон. Это значительно сокращает количество итераций вашего внутреннего цикла!

Вот идея (большинства «пространственных оптимизаций»): разделяй и властвуй; здесь вы разделите свое пространство, и затем вы сможете заблаговременно отклонить обработку большого количества не относящихся к делу «визирований» с минимальными усилиями (добавленное усилие - это тест с перекрытием прямоугольников, но каждый тест отклоняет несколько визирований, ваш текущий код проверяет каждый прицельно для актуальности).

На втором шаге также примените некоторые очевидные оптимизации кода: например, minL и maxL не меняются для каждого столбца. Вычисление minL и maxL можно перенести во внешний цикл (непосредственно перед for( int column=0; ...).

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

maxL=boxes[0][0].latitude;
minL=boxes[rows-1][0].latitude;
incL=maxL-minL;
for( int row = 0; row < rows; row++ )
{
    for( int column = 0; column < columns; column++ )
    {
        speciesPerBox=0;
        minG=boxes[row][column].longitude;
        if (column!=columns-1) {
            maxG=boxes[row][column+1].longitude;
        } else {
            maxG=buttomRight.longitude;
        }
        ...
        ...
    }
    ...

    minL = maxL; // left edge = right edge of previous step
    maxL += incL; // increment right edge
    if( maxL >= 90 ) maxL -= 90; // check your scale, i assume 90°
}

Возможно, это также работает для цикла долготы, но долгота может быть неравномерно распределена (т. Е. "IncG" отличается на каждом шаге).

Обратите внимание, что пространственная оптимизация будет иметь огромное значение , оптимизация контуров - только небольшая (но все же стоящая) разница.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...