25 нояб. 2011 г.

whoosh-appengine–полнотекстовый поиск для Google App Engine

На маленьких примерах работает хорошо, есть записей какое-то ощутимое количества или какие-то из них большие (не выяснял что именно) – просто перестает работать с исключением.
ResponseTooLargeError: The response from API call datastore_v3.RunQuery() was too large.
Для проба предложил ему проиндексировать пробную базу писем около 1000 штук, меньше чем по 30кб текста (обычно значительно меньше).
После 200-300 штук это исключение вылезало что при записи, что при попытке чтения из хранилища, при этом по объему индексов понятно, что там скорее всего ничего особо небыло (меньше 2-3 мегабайтов суммарно все объекты).
P.S. возможно это проблема Python 2.7 в режиме threadsafe: yes, видел описание похожего бага.
https://github.com/tallstreet/Whoosh-AppEngine
http://code.google.com/p/googleappengine/issues/detail?id=6282
Update: Попробовал использовать после исправления ошибки - теперь GAE нехватает памяти для работы с индексом. Пока пользуюсь Google Cloud SQL, жду полнотекстового поиска.

Обработать все данные в Google App Engine

Иногда возникает ситуация, когда нужно что-то сделать со всеми объектами в хранилище, либо со всеми объектами одного типа.

делается это просто:

1. Скачать с http://code.google.com/intl/en/appengine/downloads.html файл “MapReduce Bundle”

2. Положить папку mapreduce из архива в корень проекта

3. Создать файл mapreduce.yaml с описанием обработчика, например:

mapreduce:
- name: onetimetask
  mapper:
    input_reader: mapreduce.input_readers.DatastoreKeyInputReader
    handler: pages.OneTimeTask.process
    params:
    - name: entity_kind
      default: EMail
    - name: shard_count
      default: 2

означает, что обработчиком будет функция process в модуле pages.OneTimeTask, в функцию передается  одно значение, в данном случае это ключ объекта типа EMail, обработку вести в два потока.

4. Создать функцию, указанную в параметре handler, например

def process(key):

    logging.debug(str(key))

5. Зайти на страницу /mapreduce и запустить задание кнопкой.

Более подробное описание

http://code.google.com/p/appengine-mapreduce/wiki/UserGuidePython

16 нояб. 2011 г.

Скрыть содержимое буфера от программ, следящих за его изменением

WIN_API

1. Зарегистрировать формат "Clipboard Viewer Ignore", формат должен называться именно так, как тут написано.

CF_CLIPBOARD_VIEWER_IGNORE = (CLIPFORMAT)RegisterClipboardFormat(_T("Clipboard Viewer Ignore"))

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

SetClipboardData(CF_CLIPBOARD_VIEWER_IGNORE, “MyProgram”);
SetClipboardData(CF_TEXT, content);

 

Для C#:

DataObject d = new System.Windows.Forms.DataObject();

doData.SetData("Clipboard Viewer Ignore", false, “MyProgram”);

doData.SetText(“Content”);

Clipboard.SetDataObject(doData);

9 нояб. 2011 г.

Google Cloud SQL

Пару дней назад получил доступ к тестирование Google Cloud SQL.

Выглядит это как собственные полноценные MySQL-сервера 5.1, к ним можно подключаться из Google App Engine и (через специальный Java-Driver) снаружи. Есть импорт и экспорт через файлы Google Storage for developers.

Есть доступ к Web-консоли, где можно создавать новые сервера, изменять настройки имеющихся и выполнять произвольные SQL-запросы.

Внутри каждого сервера можно создавать свои базы данных, своих пользователей, пароли и т.п., можно указывать у каких GAE-приложений есть доступ к каждому экземпляру MySQL, т.е. несколько разных приложений могут одновременно иметь доступ к одному экземпляру MySQL и работать с общими данными.

Работает полнотекстовый поиск (собственно для него сейчас MySQL и нужен).

Подключение из Python выглядит так:

conn = rdbms.connect(instance='blabla:bla', database='db_name')

Запросы к базе выполняются через стандартный Python-интерфейс DB-API 2.0, например так:

cursor = conn.cursor()
        cursor.execute('INSERT INTO `email` (`id`, `time`, `from`, `to`, `subject`, `comment`, `text`) VALUES (%s, %s, %s, %s, %s, %s, %s)',
                [email.id(), email.Time.strftime('%Y-%m-%d--%H-%M-%S'), email.From, email.To, email.Subject, email.Comment, email.Text])
        cursor.close()
        conn.close()

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

Мне понравилась возможность совмещать нереляционное и реляционное хранилище.

Про скорость работы пока ничего не понятно – объем данных пока маленький.