【问题标题】:Django DRF elastic search dsl, Apply functional boosting based on another field numerical valueDjango DRF弹性搜索dsl,基于另一个字段数值应用功能提升
【发布时间】:2021-07-04 20:46:30
【问题描述】:

我正在尝试根据另一个字段数值(该字段在另一个模型中)调整我的字段搜索结果的相关性。查看ES documentation 似乎功能提升是我的用例所需要的。

请注意,我使用的是django-elasticsearch-dsl;包。

我的用例:

  1. 我有一个搜索字段,用户可以在其中根据公司名称搜索公司。
  2. 我想返回与查询匹配的公司名称,其中排序(相关性)取决于公司的净资产,其中数字越大,相关性越高(另一个模型中的字段)

模型定义:

class Company(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255, blank=False, null=False)

    def __str__(self):
        return self.name

class CompanyNetAsset(models.Model):
    id = models.AutoField(primary_key=True)
    assets = models.IntegerField
    company_id = models.ForeignKey('Company', on_delete=models.PROTECT, blank=True, null=True)

    def __str__(self):
        return self.name

我的 es 文档:

...
custom_stop_words = token_filter(
    'custom_stopwords',
    type='stop',
    ignore_case=True,
    stopwords=['the', 'and']

)


html_strip = analyzer(
    'html_strip',
    tokenizer="standard",
    filter=["lowercase", "asciifolding", custom_stop_words],
    char_filter=["html_strip"],
)


@INDEX.doc_type
class CompanyDocument(Document):
    id = fields.IntegerField(attr='id')

    name = fields.TextField(
        analyzer=html_strip,
        fields={
            'raw': fields.TextField(analyzer='keyword'),
        }
    )

    class Django:
        model = Company

这里是 DocumentViewSet:

class CompanyDocumentViewSet(DocumentViewSet):
    """The Company Document view."""
    serializer_class = CompanyDocumentSerializer
    lookup_field = 'id'
    document = CompanyDocument
    filter_backends = [
        FilteringFilterBackend,
        SearchFilterBackend,
    ]
    search_fields = (
        'name'
    )

    filter_fields = {
        'id': None,
        'name': 'name.raw',

    }

知道如何使用 drf ES 包实现这一点吗?

更新

这是一个示例查询:

 /api/v1/employers/companies/?search=name:foundation%20center

 "results": [
        {
            "id": 469329,
            "name": "THE FOUNDATION CENTER",
            "city": "NEW YORK",
            "state": "NY"
        },
        {
            "id": 323012,
            "name": "OVERTURE CENTER FOUNDATION",
            "city": "MADISON",
            "state": "WI"
        },
        {
            "id": 367286,
            "name": "PEACE CENTER FOUNDATION",
            "city": "GREENVILLE",
            "state": "SC"
        },
       ...

这是文档的子输出:

{'settings': {'number_of_shards': 1,
  'number_of_replicas': 1,
  'analysis': {'analyzer': {'html_strip': {'tokenizer': 'standard',
     'filter': ['lowercase', 'asciifolding', 'custom_stopwords'],
     'char_filter': ['html_strip'],
     'type': 'custom'}},
   'filter': {'custom_stopwords': {'ignore_case': True,
     'stopwords': ['the', 'and'],
     'type': 'stop'}}}},
 'mappings': {'properties': {'id': {'type': 'integer'},
   'city': {'type': 'text'},
   'state': {'type': 'text'},
   'name': {'analyzer': 'html_strip',
    'fields': {'raw': {'analyzer': 'keyword', 'type': 'text'}},
    'type': 'text'}}}}

【问题讨论】:

  • 您分享的文档链接涉及一个名为“App Search”的 ES 产品。不过,我想您没有使用 App Search?其次,你能分享你的查询和一些原始的 JSON 公司文档吗?
  • 更新了我的问题:)

标签: python django elasticsearch django-rest-framework


【解决方案1】:

ES 不支持查询时连接,因此您需要在 Company 模型中复制 CompanyNetAsset 属性才能让 assets 影响您的排序。

实际上,像这样调整Company 模型:

class Company(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255, blank=False, null=False)
    assets = models.IntegerField

    def __str__(self):
        return self.name

然后调整Document

@INDEX.doc_type
class CompanyDocument(Document):
    id = fields.IntegerField(attr='id')

    name = fields.TextField(
        analyzer=html_strip,
        fields={
            'raw': fields.TextField(analyzer='keyword'),
        }
    )

    assets = fields.IntegerField(attr='assets')

    class Django:
        model = Company

最后,重新索引您的文档并定义排序:

class CompanyDocumentViewSet(DocumentViewSet):
    """The Company Document view."""
    serializer_class = CompanyDocumentSerializer
    lookup_field = 'id'
    document = CompanyDocument
    filter_backends = [
        FilteringFilterBackend,
        SearchFilterBackend,
    ]
    search_fields = (
        'name'
    )

    filter_fields = {
        'id': None,
        'name': 'name.raw',

    }
   
    # Define ordering fields        # <--
    ordering_fields = {
        'assets': None
    }

    # Specify default ordering      
    ordering = ('assets')

要强制执行sort order via the URI,请运行:

GET /api/v1/employers/companies/?search=name:foundation%20center&ordering=-assets

【讨论】:

  • 这个@Cyzanfar运气好吗?
  • 嘿!感谢您的回答。在这种情况下,如何为资产指定 DESC 排序?
  • 不客气!刚刚更新了我的答案。只需使用?ordering=-assetsminus 用于降序,没有减号用于升序)
  • 在索引时我可以做些什么来应用一些权重,从而使 company_name 与其资产更相关?
  • 有道理,谢谢建议!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-06
  • 1970-01-01
  • 2012-12-30
  • 2018-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多