I am building a Scala API that talks to Elasticsearch using Elastic4s.
One response I receive from Elastic4s is of the type SearchHit and has the structure:
SearchHit(id: String,
index: String,
`type`: String,
score: Float,
private val _source: Map(name: String,
code: String,
location: Map(lat: Double, lon:Double)
)
)
I need to map this object to another object of the structure:
case class Location(id: Option[String] = None, location: GeoLocation, code: String, name: String)
where GeoLocation
is:
case class GeoLocation(lat: Double, lon: Double)
As you can see, most of the fields I need to be mapped to Location
are inside the _source
Map but I also need the id
to be mapped.
Elastic4s provides a typeclass that will help. It's called HitReader
(although it might change name in version 6 - to be released), and if you implement this for your type Location
then you can call .to[T]
on the search results.
object LocationHitReader extends HitReader {
def read(hit: Hit): Either[Throwable, T] = ...
}
Implementing this by hand doesn't get you much further than where you are at the moment, but elastic4s then provides implementations using the common json backends - Jackson, Json4s, Circe, Spray-Json so you don't have to do anything.
If you use Jackson for example, then you add elastic4s-jackson
to your classpath and then add the following import above your search results.
import ElasticJackson.Implicits._
Then, on your search result, you can call .to[Location]
to get a Seq[Location]
or .safeTo[Location]
to get an Seq[Either[T, Location]
To get the id out as well, you could create a custom HitReader
which delegates to the library created one, adding the id.