barseghyanartur / graphene-elastic

Graphene Elasticsearch/OpenSearch (DSL) integration
https://pypi.org/project/graphene-elastic/
71 stars 17 forks source link

Retrieving ES relevancy score? #36

Closed coreyculler closed 4 years ago

coreyculler commented 4 years ago

Hello, first off let me say that I love this integration and that it has made integrating ES with Graphene very easy. However, I am curious if it is possible to retrieve the calculated relevancy score of each search result? If it is possible, how would this be done using this library?

barseghyanartur commented 4 years ago

It should be possible to expose _score (however, it's not always available). Let me know if you have trouble implementing this. Eventually, PRs are welcome.

coreyculler commented 4 years ago

How would this be done? Would I have to create a custom resolver to retrieve the _score attribute? Is that attribute going to be available on the parent object within an ElasticsearchObjectType resolver?

barseghyanartur commented 4 years ago

Yep. Most likely, through a filter backend. It should be done in a declarative, non-breaking manner. Somewhat, like in highlight, but much simpler.

barseghyanartur commented 4 years ago

Check this (not yet released, just pushed into master):

from graphene import Node
from graphene_elastic import ElasticsearchObjectType
from graphene_elastic.filter_backends import (
    # ...
    ScoreFilterBackend,
    OrderingFilterBackend,
    # ...
)
from search_index.documents import Post as PostDocument

class Post(ElasticsearchObjectType):

    class Meta:

        document = PostDocument
        interfaces = (Node,)
        filter_backends = [
            # ...
            ScoreFilterBackend,
            OrderingFilterBackend,
            # ...
        ]

        # For `OrderingFilterBackend` backend
        ordering_fields = {
            # The dictionary key (in this case `tags`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value (in this case `tags.raw`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'title': 'title.raw',

            # The dictionary key (in this case `created_at`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value (in this case `created_at`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'created_at': 'created_at',

            # The dictionary key (in this case `num_views`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value (in this case `num_views`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'num_views': 'num_views',

            # Score
            'score': '_score',
        }

Do make sure you have added ordering results by score (as shown in ordering_fields above).

Query like this:

query PostsQuery {
      allPostDocuments(
            search:{query:"Budget"},
            filter:{category:{value:"Elastic"}},
            ordering:{score:DESC}
      ) {
        edges {
          node {
            id
            title
            category
            content
            createdAt
            score
          }
        }
      }
    }

Will produce results similar to these:

{
  "data": {
    "allPostDocuments": {
      "edges": [
        {
          "node": {
            "id": "UG9zdDpMNnBiV1hNQjhYRzdJclZ2X20waA==",
            "title": "Budget.",
            "category": "Elastic",
            "content": "Bed television public teacher behind human up.\nMind anyone politics ball cost wife try adult. College work for.\nPlay five ten not sort energy.\nCommon word behind spring. All behind voice policy.",
            "createdAt": "1973-03-12T00:00:00",
            "score": 20.420774
          }
        },
       ]
    }
  }
}
coreyculler commented 4 years ago

Oh wow, thanks for the quick code update! I'll try it out tomorrow.

barseghyanartur commented 4 years ago

@coreyculler:

Some more work is done on this. It's now possible (in master) to allow sorting on score (if added as option to the ordering_fields). See updated example.

barseghyanartur commented 4 years ago

Released in 0.6.3.