← На главную

Scala и полнотекстовый поиск с Amazon CloudSearch

CloudSearch является сервисом полнотекстового поиска в облаке Amazon’а. То есть, что-то вроде ElasticSearch или Solr, который не обязательно понимать, главное любить и кормить вовремя не нужно настраивать и поддерживать, главное вовремя оплачивать. В этой заметке будет показан простой пример использования Amazon CloudSearch на языке Scala.

Настройка Amazon CloudSearch через веб-интерфейс до безобразия проста, поэтому не будем на ней даже останавливаться, тем более, что веб-интерфейсы все равно часто меняются.

А вот, собственно, и код:

import com.amazonaws.auth.BasicAWSCredentials import com.amazonaws.services.cloudsearchdomain._ import com.amazonaws.services.cloudsearchdomain.model._ import org.json4s._ import org.json4s.jackson.JsonMethods._ import java.io._ import java.nio.charset._ import scala.collection.JavaConverters._ object CloudSearchExample extends App { val cloudsearchEndpoint = "https://abcefg.cloudsearch.amazonaws.com" val accessKey = "ACCESSKEY123" val secretKey = "SECRETKEY456" val credentials = new BasicAWSCredentials(accessKey, secretKey) val client = new AmazonCloudSearchDomainClient(credentials) client.setEndpoint(cloudsearchEndpoint) val docType = "message" val docTypeLen = docType.length // -------- upload -------- { val j = compact(render(JArray(List( JObject(List( "type" -> JString("add"), "id" -> JString(s"${docType}23456"), "fields" -> JObject(List( "text" -> JString("test test"), "type" -> JString(docType) )) )) )))) val bytes = j.getBytes(StandardCharsets.UTF_8) val stream = new ByteArrayInputStream(bytes) val req = new UploadDocumentsRequest() req.setContentType("application/json") req.setContentLength(bytes.length.toLong) req.setDocuments(stream) val res = client.uploadDocuments(req) println(res.toString) } // -------- search -------- { val req = new SearchRequest req.setQuery(s"""text:"test test" AND type:"${docType}" """) req.setQueryParser(QueryParser.Lucene) val res = client.search(req) val hits = res.getHits.getHit.asScala val ids = hits.map(_.getId).filter(_.startsWith(docType)) .map(_.drop(docTypeLen).toLong) println(s"Ids: $ids") } }

Как видите, приходится построить немного JSON-а вручную, воспользовавшись уже знакомым нам json4s. Обратите внимание, что в строке:

req.setQuery(s"""text:"test test" AND type:"${docType}" """)

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

В остальном, как мне кажется, пример предельно прост и не нуждается в особых пояснениях. Шлется запрос на добавление:

"type" -> JString("add")

… документа с определенным id и полями, затем посылается запрос на поиск документа по полям. Возвращается список наиболее релевантных документов, из него выдираются id найденных документов и показываются пользователю. В реальном приложении вам, понятное дело, придется завести пул с нитками ОС и обернуть все хождения в CloudSearch в футуры, так как вряд ли вы хотите просто брать и делать блокирующие вызовы в своем бэкенде.

А работаете ли вы с CloudSearch или иной системой полнотекстового поиска?

Дополнение: Также вас может заинтересовать пост Основы полнотекстового поиска в PostgreSQL.