【发布时间】:2020-10-07 14:49:54
【问题描述】:
三个参数来自前端:
-
State- 字符串 -
Categories- 一个字符串数组。字符串可以由多个单词组成。 -
Tags- 类似于类别。
所有参数都是可选的。
如果是多个传输,需要通过AND来实现它们的bundle(和state、category、tag的巧合)。 如果提交了多个categories 或tags,则会为其中至少一个进行匹配。
也就是说,如果一个带有参数的请求到达
{"state": "Alaska", "categories": ["category 1", "category 2"]}
答案将是
-
state = Alaska,categories = category 1; -
state = Alaska, categories = category 2; -
state = Alaska, categories = [category 1, category 2]; -
state = Alaska, categories = [category 1, category 3](至少有一个要求的类别)。
不适合
state = Alabama, categories = category 1state = Alaska, categories = 3-
state = Alaska, categories = 1 category(类别名称应该是 1-in-1"category 1" != "1 category")
到elastikserch 我从python (3.7) 发送请求。拿了一个图书馆
elasticsearch-dsl
通过Q 对象收集三个过滤器(在其中使用match)。
combined_filter = state_filter & categories_filter & tags_filter
categories和tags的列表分为subfilters through OR。
query = queries.pop()
for item in queries:
query |= item
这样的请求是为elasticsearch 创建的。
Bool(minimum_should_match=1,
must=[Match(state='Alaska'), MatchAll()],
should=[Match(categories='category 1'), Match(categories='category 2')]
)
为什么这个逻辑通过不准确 category / tag 名称查找条目?
from typing import List
from elasticsearch import Elasticsearch
from elasticsearch_dsl import Q, Search
from flask import request
from flask.views import MethodView
es = Elasticsearch()
class ArticleSearchAPIView(MethodView):
"""
Search articles using ElasticSearch
"""
@staticmethod
def filter_create(queries: List[Q]) -> Q:
"""
Creates Q.OR filter
"""
query = queries.pop()
for item in queries:
query |= item
return query
def get(self) -> dict:
"""
Search article
First request - with empty params
"""
search = Search(using=es, index=ArticleModel.__tablename__)
state_filter = categories_filter = tags_filter = Q()
result = "Articles not found."
data = request.get_json()
categories = data.get("categories")
tags = data.get("tags")
state = data.get("state")
if state:
state_filter = Q("match", state=state)
if categories:
queries = [Q("match", categories=value) for value in categories]
categories_filter = self.filter_create(queries)
if tags:
queries = [Q("match", tags=value) for value in tags]
tags_filter = self.filter_create(queries)
combined_filter = state_filter & categories_filter & tags_filter
found = (
search.filter(combined_filter)
.execute()
.to_dict()["hits"]
.get("hits")
)
if found:
result = [article["_source"] for article in found]
return {"response": result}
更新
Article and Category 和 Article and Tag - MTM 之间的关系
映射
{
"articles": {
"mappings": {
"properties": {
...
"categories": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"state": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"tags": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
...
}
}
}
}
【问题讨论】:
标签: python python-3.x elasticsearch flask elasticsearch-dsl