Статьи

Google App Engine Полнотекстовый поиск с облачным SQL

Многие разработчики Google AppEngine ждали возможности полнотекстового поиска, особенно от Google, крупнейшей поисковой системы в Интернете. Я был очень рад видеть, что команда Google работает над этим, как вы можете проверить в сессии Google I / O 2011: Полнотекстовый поиск Бо Маевски, Гед Эллис . Насколько я знаю, очень многообещающая служба индексации пока недоступна.

В этой статье я объясню, как вы можете обеспечить своего рода полнотекстовый поиск в своем приложении, используя службы, доступные службам App Engine.

В моем конкретном случае использования я не требую большого количества функций, мне просто нужно просто найти строку в различных атрибутах моих сущностей независимо от регистра и возможные специальные символы (такие как è, é,…). Я далеко не эксперт Google Datastore API, но я не нашел простого способа добиться этого напрямую с помощью Java API. Чтобы решить эту проблему, я скопировал часть моих данных в Google Cloud SQL, чтобы использовать возможности полнотекстового поиска MySQL.

Предпосылки
Для решения следующих задач вам необходимо:

содержание

В следующих параграфах я объясню основы интеграции Cloud SQL для полнотекстового поиска, но вы можете, если хотите, перейти к:

1. Создание статей сущностей
Начните с создания нескольких простых объектов с некоторыми атрибутами, например, с именем объекта Article, с атрибутами title и body.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
 
//...
//...
 
  Entity article = new Entity("Article");
  article.setProperty("title", "MySQL Tutorial");
  article.setProperty("body", "DBMS stands for DataBase ...");
  datastore.put(article);
 
  article = new Entity("Article");
  article.setProperty("title", "Datastore Index Selection and Advanced Search");
  article.setProperty("body", "Learn how recent improvements to the query planner ... function in your application");
  datastore.put(article);

Если вы загляните в Datastore API, или даже в JDO или JPA, у вас не будет простого способа найти все статьи, связанные с триатлоном, базой данных или сущностями. Google DataStore не поддерживает предложение где с «ИЛИ» между различными полями; и я не хочу упоминать тот факт, что невозможно игнорировать текстовый случай простым способом.

Вот почему нам нужны некоторые полнотекстовые функции. Некоторые из вас наверняка думают об использовании Apache Lucene, и да, это возможно. Вы можете использовать, например, проект GAELucene: http://code.google.com/p/gaelucene/ . Я использую другой подход, может быть менее продвинутым с точки зрения параметров «индексация / поиск», но достаточным для моего варианта использования:

  • Я храню текстовые значения, по которым я хочу выполнить поиск, в Google Cloud SQL и использую полнотекстовые функции MySQL.

2. Создайте таблицу SQL для хранения текстовых значений (в среде разработки)

При использовании Google AppEngine доступ к экземплярам Cloud SQL осуществляется с использованием определенного драйвера и конфигурации, которые мы увидим позже. На данный момент мы все еще находимся в среде разработки, здесь вы должны использовать свой локальный экземпляр MySQL.

В этом конкретном случае использования мы скопируем в таблицу два поля и добавим новый уникальный ключ на основе ключа объекта. Итак, SQL для создания этого:

01
02
03
04
05
06
07
08
09
10
11
12
CREATE SCHEMA search_values DEFAULT CHARACTER SET utf8 ;
 
USE search_values;
 
 
CREATE TABLE articles  (
  entity_key varchar(250),
  title text,
  body text,
  PRIMARY KEY RESULTS_PK (entity_key),
  FULLTEXT (title,body)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Строки 1 и 3 предназначены для создания схемы базы данных и ее использования; Затем сценарий создает таблицу, которая будет содержать копию заголовка и тела от объекта.

3. Настройте среду разработки

Этот раздел представляет собой краткое объяснение документации по облачному SQL: Начало работы: Java

  1. Скопируйте драйвер MySQL JDBC в каталог SDK Google App Engine в каталоге /lib/impl/ . Вы можете скачать драйвер MySQL JDBC здесь .
  2. В Eclipse выберите свой пакет Java.
  3. Нажмите « Выполнить» > « Выполнить настройки» .
  4. Разверните пункт меню Веб-приложение .
  5. Добавьте следующие строки в панель VM Arguments :
    1
    2
    3
    -Drdbms.server=local
    -Drdbms.driver=com.mysql.jdbc.Driver
    -Drdbms.url=jdbc:mysql://localhost:3306/search_values?user=username&password=password
  6. Нажмите вкладку Classpath .
  7. Выберите ваш проект и нажмите Add External JARs…
  8. Перейдите в каталог SDK Google App Engine, затем lib/impl и выберите файл JAR драйвера JDBC. Нажмите Открыть . JAR драйвера указан в разделе « Записи пользователя» .
  9. Нажмите Применить .

Ваша среда разработки готова к использованию вашей локальной базы данных MySQL. Давайте теперь использовать эту базу данных.

4. Используйте свою таблицу MySQL и скопируйте текстовые значения из Google Datastore в MySQL Table

Копировать данные из сущности Datastore в таблицу довольно просто:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Connection conn = null;
try {
 DriverManager.registerDriver(new AppEngineDriver());
 conn = DriverManager.getConnection("jdbc:google:rdbms://[your db instance]/search_values");
 conn.setAutoCommit(false); 
 String statement = "REPLACE INTO articles (entity_key, title, body) VALUES( ? , ? , ? )";
 PreparedStatement stmt = conn.prepareStatement(statement);
 
 DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
 Query q = new Query("Article");  
 PreparedQuery pq = datastore.prepare(q);
 
 // loop on each entity and insert the values in the SQL Table
 for (Entity result : pq.asIterable()) {
  stmt.setString(1,  KeyFactory.keyToString(result.getKey())   );
  stmt.setString(2,  result.getProperty("title").toString() );
  stmt.setString(3,  result.getProperty("body").toString() );
  stmt.executeUpdate();
  conn.commit();
 }
 
 
 
} catch (SQLException e) {
 e.printStackTrace();
} finally {
 if (conn != null)
  try {
   conn.close();
  } catch (SQLException ignore) {}
}

Некоторые специальные вещи здесь, по сравнению со стандартной веб-разработкой Java:

  • Я управляю соединением напрямую в своем коде ( я еще не посмотрел, могу ли я использовать источники данных / пул соединений в контексте Google AppEngine )
  • Строка # 3: регистрация драйвера AppEngine, отвечающего за управление соединением, особенно работа в -local MySQL- или в производственном режиме -CloudSQL-.
  • Строка № 4: Получить соединение. Интересно отметить, что при разработке URL-адрес соединения берется из переменной среды Drdbms.url, которую вы установили ранее. Позже мы увидим, как мы перенесем это в облако. Это волшебная часть AppEngineDriver, которая управляет различными типами соединений Local MySQL или CloudSQL в зависимости от контекста
  • После этих строк код довольно прост:
    • Получить все сущности Статьи из хранилища данных и цикл
    • «Upsert» запись базы данных (СМЕНА СМЕНЫ INTO)
  • Строка № 15 хранит ключ сущности в безопасной строке, используя метод KeyFactory.keyToString () .

Если вы хотите протестировать этот код, просто поместите эти строки в сервлет, чтобы «синхронизировать» данные из хранилища данных в таблицу MySQL. Очевидно, этот код предназначен только для изучения и должен быть лучше интегрирован в реальное приложение; начиная с отправки данных в базу данных, когда объекты создаются / обновляются (и удаляются;)). Пример кода, доступного на GitHub, содержит эти методы.

5. Реализуйте метод поиска

Цель состоит в простом возвращении списка сущностей, возвращаемых по простому критерию поиска:

  • public Iterable searchEntities (Строковый запрос)

Логика здесь довольно проста:

  1. Выполнить запрос SQL
  2. Для каждого результата получите сущность, используя ключ
  3. Возврат списка сущностей
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public Iterable
 
  searchEntity(String query) {
 List
  
   results = new ArrayList
   
   ();
 Connection conn = null;
 try {
  DriverManager.registerDriver(new AppEngineDriver());
  conn = DriverManager.getConnection("jdbc:google:rdbms://[your db instance]/search_values");
  String statement = "SELECT entity_key FROM articles WHERE MATCH (title,body) AGAINST (? WITH QUERY EXPANSION);";
  PreparedStatement stmt = conn.prepareStatement(statement);
  stmt.setString(1, query);
  ResultSet rs = stmt.executeQuery();
  while (rs.next()) {
   String keyAsString = rs.getString(1);   
   Entity article = DatastoreServiceFactory.getDatastoreService().get( KeyFactory.stringToKey(keyAsString)  );
   results.add(article);
  }
 
 } catch (SQLException e) {
  e.printStackTrace();
 } catch (EntityNotFoundException e) {
  e.printStackTrace();
 } finally {
  if (conn != null)
   try {
    conn.close();
   } catch (SQLException ignore) {}
 }
 return results;
}

В этом методе система подключается к базе данных, а затем выполняет запрос для поиска данных, используя любой тип запроса SQL / MySQL. В этом экзамене я использую полнотекстовую функцию с « С расширением запроса ». Очевидно, что вы можете использовать любой тип SQL-запросов, например, простой оператор LIKE, если этого достаточно для вашего приложения.

С таким подходом, когда я ищу:

  • «База данных»: метод возвращает все статьи, касающиеся базы данных, mysql, RDBMS независимо от случая.
  • «Index» — метод возвращает все статьи, в которых говорится об индексации / индексировании или поиске.

6. Развертывание в GAE

После того как вы создали свое приложение, активировали и настроили свой экземпляр CloudSQL ( здесь) , вы можете развернуть свое приложение и наслаждаться простым способом использования полнотекстового поиска с GAE.

Вывод

В этой статье я объяснил, как вы можете использовать Google Cloud SQL для простой поддержки запросов полнотекстового поиска на основе полнотекстовой поддержки MySQL.

Фрагменты кода, которыми я поделился в этой статье, действительно просты и не готовы для реального использования, но все же являются хорошей отправной точкой. Например, я использовал это в своем приложении с очередями GAE, чтобы управлять своими индексами для большего объема данных.

Как было сказано ранее, вы можете протестировать приложение онлайн по адресу http://gae-fulltext-search.appspot.com/, а исходный код доступен на GitHub: https://github.com/tgrall/gae-full-text-. поиск

Справка: полнотекстовый поиск Google AppEngine с облачным SQL от нашего партнера по JCG Тугдуала Гралла в блоге Tug’s Blog .