Indexing multiply nested models with django_elasticsearch_dsl
I'm trying to use Elasticsearch in my Django app. I have Lemma models that can have multiple Forms with one citation form that can, in turn, have multiple Spellings. I'm trying to execute a search on (1) the Lemma's citation form, (2) any Lemma's Form's citation form, or (3) any Lemma's Form's Spelling's Latin character spelling.
The structure in my models.py
:
class Lemma(models.Model):
cf = models.CharField(max_length=200)
pos = models.ForeignKey(Pos, blank=True, null=True, on_delete=models.SET_NULL)
notes = models.TextField(blank=True)
sortform = models.CharField(max_length=200)
class LemmaDef(models.Model):
lemma = models.ForeignKey(Lemma, on_delete=models.CASCADE, related_name="definitions")
definition = models.TextField()
class Form(models.Model):
lemma = models.ForeignKey(Lemma, on_delete=models.CASCADE, related_name="forms")
cf = models.CharField(max_length=200, blank=True)
formtype = models.ManyToManyField(FormType, blank=True)
class Spelling(models.Model):
form = models.ForeignKey(Form, on_delete=models.CASCADE, related_name="spellings")
spelling_lat = models.CharField(max_length=200)
spelling_cun = models.CharField(max_length=200, blank=True)
note = models.CharField(max_length=200, blank=True)
In documents.py
, I've got:
from django_elasticsearch_dsl import Document, fields
from django_elasticsearch_dsl.registries import registry
from .models import Lemma, Pos, LemmaDef, Form, Spelling
@registry.register_document
class LemmaDocument(Document):
pos = fields.ObjectField(properties={
"term": fields.TextField()
})
definitions = fields.ObjectField(properties={
"definition": fields.TextField()
})
forms = fields.ObjectField(properties={
"cf": fields.TextField(),
"spellings": fields.ObjectField(properties={
"spelling_lat": fields.TextField()
})
})
class Index:
name = "lemma"
settings = {
"number_of_shards": 1,
"number_of_replicas": 0
}
class Django:
model = Lemma
fields = [
"id",
"cf",
"sortform",
"notes",
]
related_models = [Pos, LemmaDef, Form, Spelling]
def get_instances_from_related(self, related_instance):
if isinstance(related_instance, Pos):
related_instance.lemma_set.all()
elif isinstance(related_instance, LemmaDef):
related_instance.lemma
elif isinstance(related_instance, Form):
related_instance.lemma
elif isinstance(related_instance, Spelling):
related_instance.form.lemma
When I run my searches, searches on definitions.definition
returns the expected results, but searches on fields in forms.cf
or forms.spellings.spelling_lat
don't return anything.
The view is executing:
class LemmaSearchView(LemmaListView):
template_name = "emedict/lemma_search.html"
def get(self, request, *args, **kwargs):
form = LemmaAdvancedSearchForm(self.request.GET or None)
if form.is_valid():
term = request.GET["search_term"]
match request.GET["search_type"]:
case "lemma":
fields = [
"cf", "forms.cf", "forms.spellings.spelling_lat", "sortform"
]
case "definition":
fields = ["definitions.definition"]
case _:
fields = [
"cf", "forms.cf", "forms.spellings.spelling_lat", "sortform"
]
# TODO: convert sub nums to regular?
q = edsl.Q(
"multi_match",
query = term,
fields = fields,
fuzziness = "auto"
)
search = LemmaDocument.search().query(q)
qs: QuerySet = search.to_queryset()
self.lemmalist = qs.distinct().order_by("sortform")
return self.render_to_response(self.get_context_data(form=form))
Is there something I'm not understanding with searches that go down two nested levels?