I am following the official tutorial of Elasticsearch using Python with Flask. I implemented the full text matching search, but I wanted to extend the functionality to find nearest locations. I found again from the official documentation geo-distance query. I tried the query, but it doesn't work on my side. Here is my creation of the Search object:
from pprint import pprint
from elasticsearch import Elasticsearch
from decouple import config
from managers.home_manager import HomeManager
from schemas.response.home_response import HomeResponseSchema, PinSchema
mapping = {
"mappings": {
"properties": {"pin": {"properties": {"location": {"type": "geo_point"}}}}
}
}
class Search:
def __init__(self) -> None:
self.es = Elasticsearch(
api_key=config("ELASTIC_API_KEY"), cloud_id=config("ELASTIC_CLOUD_ID")
)
client_info = self.es.info()
print("Connected to Elasticsearch!")
pprint(client_info.body)
def create_index(self):
self.es.indices.delete(index="real_estate_homes", ignore_unavailable=True)
self.es.indices.create(index="real_estate_homes", body=mapping)
def insert_document(self, document):
return self.es.index(index="real_estate_homes", body=document)
def insert_documents(self, documents):
operations = []
for document in documents:
operations.append({"index": {"_index": "real_estate_homes"}})
operations.append(document)
return self.es.bulk(operations=operations)
def reindex_homes(self):
self.create_index()
homes = HomeManager.select_all_homes()
pins = []
for home in homes:
pin = {
"location": {"lat": float(home.latitude), "lon": float(home.longitude)}
}
pins.append(pin)
return self.insert_documents(pins)
def search(self, **query_args):
return self.es.search(index="real_estate_homes", **query_args)
es = Search()
I want to mention that I tried to dump json files using PinSchema object.
Here is the code with the queiries:
from flask_restful import Resource
from managers.home_manager import HomeManager
from search import es
from schemas.response.home_response import HomeResponseSchema
class ElasticResource(Resource):
def get(self, home_id):
print(home_id)
home = HomeManager.select_home_by_id(home_id)
geo_query = es.search(
body={
"query": {
"bool": {
"must": {"match_all": {}},
"filter": {
"geo_distance": {
"distance": "2000km",
"pin.location": {"lat": 43, "lon": 27},
}
},
}
}
}
)
print(geo_query)
result = es.search(
query={
"bool": {
"must": {"match": {"city": {"query": home.city}}},
"must_not": {"match": {"id": {"query": home.id}}},
}
}
)
print(result["hits"]["hits"])
if len(result["hits"]["hits"]) == 0:
return "No results."
suggested_homes = [
suggested_home["_source"] for suggested_home in result["hits"]["hits"]
]
resp_schema = HomeResponseSchema()
return resp_schema.dump(suggested_homes, many=True), 200
Can anybody help me to find the problem and receive matches?
I tried to find solutions in StackOverflow, but they didn't worked too.
I took a closer look at the data which is sent to Elasticsearch. I can see that the construction of the dictionary pin is wrong:
def reindex_homes(self):
self.create_index()
homes = HomeManager.select_all_homes()
pins = []
for home in homes:
pin = {
"pin": {"location": {"lat": float(home.latitude), "lon": float(home.longitude)}}
}
pins.append(pin)
return self.insert_documents(pins)