2

I'm try to make a Http request with Haskell (Aeson) to Elasticsearch.

The Elasticsearch body looks so:

{   
    "query": {
        "function_score": {
            "query": {
                "bool": {
                    "should": [
                        {"term": {"word_n_gram": "str"}},
                        {"term": {"word_n_gram": "not"}}                        
                    ]
                }
            },
            "functions": [
                {
                    "script_score": {
                        "script": {
                            "lang": "groovy",
                            "file": "test-score",
                            "params": {
                                "boostBy": {
                                    "str": 1,
                                    "not": 1
                                }
                            }
                        }
                    }
                }
            ]
        }
    }
}

And it works properly.

So, I made the "equivalent" in Haskell:

data QueryRequest = QueryRequest {
    query :: Query
} deriving (Eq, Generic, Show)

instance ToJSON QueryRequest

data Query = Query {
    function_score :: FunctionScore
} deriving (Eq, Generic, Show)

instance ToJSON Query

data FunctionScore = FunctionScore {
    queryIn   :: QueryIn
  , functions :: [Functions]
} deriving (Eq, Generic, Show)

instance ToJSON FunctionScore

data QueryIn = QueryIn {
    bool :: BoolQuery
} deriving (Eq, Generic, Show)

instance ToJSON QueryIn

data BoolQuery = BoolQuery {
    should :: [ShouldQuery]
} deriving (Eq, Generic, Show)

and so on...

the point is, in haskell, I can't have two times the "query" declaration that's why I wrote queryIn but, since I'm making a request, and Elasticsearch is waiting for query two times, I get this error:

FailureResponse {responseStatus = Status {statusCode = 400, statusMessage = "Bad Request"}, responseContentType = application/json;charset=UTF-8, responseBody = "{\"error\":{\"root_cause\":[{\"type\":\"parsing_exception\",\"reason\":\"no [query] registered for [queryIn]\",\"line\":1,\"col\":39}],\"type\":\"parsing_exception\",\"reason\":\"no [query] registered for [queryIn]\",\"line\":1,\"col\":39},\"status\":400}"}

which is a logic error. But I don't know how I could fix it....

I make the "RequestQuery" in this way:

toElasticSearchQuery :: T.Text -> RW.QueryRequest
toElasticSearchQuery word =
  RW.QueryRequest {
    RW.query = RW.Query {
      RW.function_score = RW.FunctionScore {
        RW.queryIn = RW.QueryIn {
          RW.bool = RW.BoolQuery {
            RW.should = toShouldQueryList (splitInNGrams word)
          }
        },
        RW.functions = [
          RW.Functions {
            RW.scriptScore = RW.ScriptScore {
              RW.script = RW.Script {
                RW.lang = scriptLang,
                RW.file = scriptFile,
                RW.params = RW.Params {
                  RW.boostBy = fixGramConter (splitInNGrams word)
                }
              }
            }
          }
        ]
      }
    }
  }

And of course, I can't write RW.query inside the RW.FunctionScore. I don't know how I can fix it, for a Response would be no problem, but for a Request, it's a problem.

Maybe someone tried something like that before.

Chuck Aguilar
  • 1,998
  • 1
  • 27
  • 50

1 Answers1

2

I fixed it. I had to redeclare the toJSON instance from aeson

instance ToJSON FunctionScore where
  toJSON (FunctionScore q f)   = object ["query" .= q, "functions" .= f]

and it works nicely.

Chuck Aguilar
  • 1,998
  • 1
  • 27
  • 50