Question

Je construis un petit moteur de recherche en utilisant Django Haystack + Elasticsearch + Django REST Framework, et j'essaie de comprendre reproduire le comportement d'un Django QuerySetc'est distinct méthode.

Mon index ressemble à ceci :

class ItemIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    item_id = indexes.IntegerField(faceted=True)

    def prepare_item_id(self, obj):
        return obj.item_id

Ce que j'aimerais pouvoir faire est le suivant :

sqs = SearchQuerySet().filter(content=my_search_query).distinct('item_id')

Cependant, Haystack's SearchQuerySet n'a pas de distinct méthode, donc je suis un peu perdu.J'ai essayé de facetter le champ, puis d'interroger Django en utilisant la liste renvoyée de item_id, mais cela fait perdre les performances d'Elasticsearch et rend également impossible l'utilisation des fonctionnalités de tri d'Elasticsearch.

Des pensées?

MODIFIER:

Exemples de données :

Exemples de données :

Item Model
==========

id  title
1   'Item 1'
2   'Item 2'
3   'Item 3'


VendorItem Model << the table in question
================

id  item_id  vendor_id  lat   lon
1   1        1          38    -122
2   2        1          38.2  -121.8
3   3        2          37.9  -121.9
4   1        2          ...   ...
5   2        2          ...   ...
6   2        3          ...   ...

Comme vous pouvez le constater, il existe plusieurs VendorItem pour le même élément. Cependant, lors de la recherche, je souhaite uniquement récupérer au plus un résultat pour chaque élément.J'ai donc besoin du item_id colonne doit être unique/distincte.

J'ai essayé le facettage sur le item_id colonne, puis en exécutant la requête suivante :

facets = SearchQuerySet().filter(content=query).facet('item_id')
counts = sqs.facet_counts()

# ids will look like: [345, 892, 123, 34,...]
ids = [i[0] for i in counts['fields']['item_id']]

items = VendorItem.objects.filter(vendor__lat__gte=latMin,
    vendor__lon__gte=lonMin, vendor__lat__lte=latMax,
    vendor__lon__lte=lonMax, item_id__in=ids).distinct(
        'item').select_related('vendor', 'item')

Le principal problème ici est que les résultats sont limités à 100 éléments et qu’ils ne peuvent pas être triés avec une botte de foin.

Était-ce utile?

La solution

Je pense que le meilleur conseil que je puisse vous donner est d’arrêter d’utiliser Haystack.

Le backend par défaut de Haystack (elasticsearch_backend.py) est principalement écrit en pensant à Solr.Il y a beaucoup de désagréments que je trouve dans haystack, mais le plus important est qu'il regroupe toutes les requêtes dans quelque chose appelé query_string.En utilisant une chaîne de requête, ils peuvent utiliser la syntaxe Lucene, mais cela signifie également perdre l'intégralité du DSL elasticsearch.La syntaxe Lucene présente certains avantages, surtout si c'est ce à quoi vous êtes habitué, mais elle est très limitante du point de vue d'ElasticSearch.

De plus, je pense que vous appliquez un concept de SGBDR à un moteur de recherche.Cela ne veut pas dire que vous ne devriez pas obtenir les résultats souhaités, mais l’approche est souvent différente.

La façon dont vous pouvez interroger et récupérer ces données peut être différente si vous n'utilisez pas haystack, car haystack crée des index d'une manière plus appropriée pour solr que pour elasticsearch.

Par exemple, lors de la création d'un nouvel index, haystack attribuera un "type" appelé "modelresult" à tous les modèles qui iront dans un index.

Supposons donc que vous ayez des entités appelées Items et d'autres entités appelées Vendoritems.

Il pourrait être approprié de les avoir tous les deux dans le même index mais avec les éléments du fournisseur comme type d'éléments du fournisseur et les éléments ayant un type d'éléments.

Lors de l'interrogation, vous interrogeriez ensuite en fonction du point de terminaison restant, quelque chose comme localhost:9200/index/type (query).La façon dont Haystack y parvient est via le module de types de contenu Django.En conséquence, il existe un champ appelé "django_ct" qui interroge la botte de foin et s'attache à toute requête que vous pourriez effectuer lorsque vous recherchez uniquement des éléments uniques.

Pour illustrer ce qui précède :

Ce point de terminaison recherche dans tous les index

`localhost:9200/`

Ce point de terminaison effectue une recherche dans tous les types d'un index :

`localhost:9200/yourindex/`

Ce point de terminaison recherche dans un type dans un index :

`localhost:9200/yourindex/yourtype/`

et ce point de terminaison recherche dans deux types spécifiés dans un index :

`localhost:9200/yourindex/yourtype,yourothertype/`

Revenons à la botte de foin, vous pouvez éventuellement obtenir des valeurs uniques en ajoutant un django_ct à votre requête, mais ce n'est probablement pas ce que vous voulez.

Ce que vous voulez vraiment faire, c'est une facette, et vous souhaiterez probablement utiliser le terme facettes.Cela pourrait être un problème dans haystack car A.) analyse tout le texte et B.) applique store=True à tous les champs (vraiment pas quelque chose que vous voulez faire dans elasticsearch, mais quelque chose que vous voulez souvent faire dans solr).

Vous pouvez commander les résultats des facettes dans elasticsearch (http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-facet.html#_ordering)

Je ne veux pas que ce soit une claque sur une botte de foin.Je pense que cela fait beaucoup de choses correctement sur le plan conceptuel.C'est particulièrement utile si tout ce que vous avez à faire est d'indexer un seul modèle (comme, par exemple, un blog) et de lui faire renvoyer rapidement des résultats.

Cela dit, je recommande fortement d'utiliser utilitaires élastiques.Certains concepts de haystack sont similaires, mais il utilise le search DSL plutôt que query_string (mais vous pouvez toujours utiliser query_string si vous le souhaitez).

Attention cependant, je ne pense pas que vous puissiez commander les facettes en utilisant elasticutils par défaut, mais vous pouvez simplement transmettre dans un dictionnaire python les facettes que vous souhaitez facet_raw méthode (quelque chose que je ne pense pas que vous puissiez faire dans une botte de foin).

Votre dernière option consiste à créer votre propre backend de botte de foin, à hériter du backend existant et à simplement ajouter quelques fonctionnalités à la méthode .facet() pour permettre la commande selon le DSL ci-dessus.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top