Skip to content

Commit

Permalink
feat(backend): 全局搜索接口支持批量查询 #2781
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangzhw8 committed Dec 25, 2023
1 parent 6e25f70 commit 41d9673
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 97 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/auto_create_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,9 @@ jobs:
uses: peter-evans/create-pull-request@v3
with:
token: "${{ secrets.WORKFLOW_ACTION_TOKEN }}"
title: 'update medium.lock'
title: 'chore: update medium.lock #1'
body: ''
branch: '${{ steps.get-current-branch.outputs.current_branch }}'
base: 'medium_lock'

- name: Auto Add Release File
id: add-release-file
Expand All @@ -99,4 +98,4 @@ jobs:
git remote add upstream https://[email protected]/TencentBlueKing/blueking-dbm
git add .
git commit -m "chore: release version ${{ steps.yaml-data.outputs.data }} #1"
git push upstream ${{ steps.get-current-branch.outputs.current_branch }}
git push upstream ${{ steps.get-current-branch.outputs.current_branch }}
4 changes: 2 additions & 2 deletions dbm-ui/backend/db_services/dbbase/resources/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ def get_topo_graph(self, request, bk_biz_id: int, cluster_id: int):
"""获取拓扑图"""
return Response(self.query_class.get_topo_graph(bk_biz_id, cluster_id))

@action(methods=["GET"], detail=False, url_path="export_cluster")
@action(methods=["POST"], detail=False, url_path="export_cluster")
def export_cluster(self, request, bk_biz_id: int):
"""导出集群数据为 excel 文件"""
cluster_ids = request.POST.get("cluster_ids")
return self.query_class.export_cluster(bk_biz_id, cluster_ids)

@action(methods=["GET"], detail=False, url_path="export_instance")
@action(methods=["POST"], detail=False, url_path="export_instance")
def export_instance(self, request, bk_biz_id: int):
"""导出实例数据为 excel 文件"""
bk_host_ids = request.POST.get("bk_host_ids")
Expand Down
157 changes: 77 additions & 80 deletions dbm-ui/backend/db_services/quick_search/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,46 @@
from backend.db_services.quick_search.constants import FilterType, ResourceType
from backend.flow.models import FlowTree
from backend.ticket.models import Ticket
from backend.utils.string import split_str_to_list


class QSearchHandler(object):
def __init__(self, bk_biz_ids=None, db_types=None, resource_types=None, filter_type=None):
def __init__(self, bk_biz_ids=None, db_types=None, resource_types=None, filter_type=None, limit=None):
self.bk_biz_ids = bk_biz_ids
self.db_types = db_types
self.resource_types = resource_types
self.filter_type = filter_type
self.limit = 10
self.limit = limit or 10

# db_type -> cluster_type
self.cluster_types = []
if self.db_types:
for db_type in self.db_types:
self.cluster_types.extend(ClusterType.db_type_to_cluster_type(db_type))

def search(self, keyword):
def search(self, keyword: str):
result = {}
target_resource_types = self.resource_types or ResourceType.get_values()
for target_resource_type in target_resource_types:
filter_func = getattr(self, f"filter_{target_resource_type}", None)
if callable(filter_func):
result[target_resource_type] = filter_func(keyword)
keyword_list = split_str_to_list(keyword)
result[target_resource_type] = filter_func(keyword_list)

return result

def generate_filter_for_str(self, filter_key, keyword_list):
"""
为字符串类型生成过滤函数
"""
if self.filter_type == FilterType.EXACT.value:
qs = Q(**{f"{filter_key}__in": keyword_list})
else:
qs = Q()
for keyword in keyword_list:
qs |= Q(**{f"{filter_key}__icontains": keyword})
return qs

def common_filter(self, objs, return_type="list", fields=None, limit=None):
"""
return_type: list | objects
Expand All @@ -58,58 +72,44 @@ def common_filter(self, objs, return_type="list", fields=None, limit=None):
limit = limit or self.limit
return list(objs[:limit].values(*fields))

def filter_cluster_name(self, keyword):
def filter_cluster_name(self, keyword_list: list):
"""过滤集群名"""

qs = Q(name=keyword) if self.filter_type == FilterType.EXACT.value else Q(name__contains=keyword)
qs = self.generate_filter_for_str("name", keyword_list)
objs = Cluster.objects.filter(qs)
return self.common_filter(objs)

def filter_cluster_domain(self, keyword):
def filter_cluster_domain(self, keyword_list: list):
"""过滤集群域名"""

qs = (
Q(immute_domain=keyword)
if self.filter_type == FilterType.EXACT.value
else Q(immute_domain__contains=keyword)
)

qs = self.generate_filter_for_str("immute_domain", keyword_list)
objs = Cluster.objects.filter(qs)
return self.common_filter(objs)

def filter_instance(self, keyword):
def filter_instance(self, keyword_list: list):
"""过滤实例"""

if self.filter_type == FilterType.EXACT.value:
qs = Q(machine__ip=keyword) | Q(name=keyword)
else:
qs = Q(machine__ip__contains=keyword) | Q(name__contains=keyword)

qs = self.generate_filter_for_str("machine__ip", keyword_list)
if self.bk_biz_ids:
qs = Q(bk_biz_id__in=self.bk_biz_ids) & qs

if self.db_types:
qs = Q(cluster_type__in=self.cluster_types) & qs

objs = (
StorageInstance.objects.filter(qs)
storage_objs = (
StorageInstance.objects.prefetch_related("cluster", "machine")
.filter(qs)
.annotate(
role=F("instance_role"),
cluster_id=F("cluster__id"),
cluster_domain=F("cluster__immute_domain"),
ip=F("machine__ip"),
)
.union(
ProxyInstance.objects.filter(qs).annotate(
role=F("access_layer"),
cluster_id=F("cluster__id"),
cluster_domain=F("cluster__immute_domain"),
ip=F("machine__ip"),
)
)
)

return objs[: self.limit].values(
proxy_objs = ProxyInstance.objects.prefetch_related("cluster", "machine").annotate(
role=F("access_layer"),
cluster_id=F("cluster__id"),
cluster_domain=F("cluster__immute_domain"),
ip=F("machine__ip"),
)
fields = [
"id",
"name",
"bk_biz_id",
Expand All @@ -123,16 +123,12 @@ def filter_instance(self, keyword):
"machine_id",
"status",
"phase",
)
]
return list(storage_objs[: self.limit].values(*fields)) + list(proxy_objs[: self.limit].values(*fields))

def filter_task(self, keyword):
def filter_task(self, keyword_list: list):
"""过滤任务"""

if self.filter_type == FilterType.EXACT.value:
qs = Q(root_id=keyword)
else:
qs = Q(root_id__contains=keyword)

qs = self.generate_filter_for_str("root_id", keyword_list)
objs = FlowTree.objects.filter(qs)

if self.bk_biz_ids:
Expand All @@ -141,20 +137,17 @@ def filter_task(self, keyword):
# TODO: db类型任务的过滤
return list(objs[: self.limit].values("uid", "bk_biz_id", "ticket_type", "root_id", "status", "created_by"))

def filter_machine(self, keyword):
def filter_machine(self, keyword_list: list):
"""过滤主机"""

bk_host_ids = [int(keyword) for keyword in keyword_list if isinstance(keyword, int) or keyword.isdigit()]
if self.filter_type == FilterType.EXACT.value:
qs = Q(ip=keyword)

try:
# fix bk_host_id expected a number but got string
keyword_int = int(keyword)
qs = qs | Q(bk_host_id=keyword_int)
except ValueError:
pass
qs = Q(ip__in=keyword_list)
if bk_host_ids:
qs = qs | Q(bk_host_id__in=bk_host_ids)
else:
qs = Q(ip__contains=keyword)
qs = Q()
for keyword in keyword_list:
qs |= Q(ip__contains=keyword)

if self.bk_biz_ids:
qs = qs & Q(bk_biz_id__in=self.bk_biz_ids)
Expand All @@ -163,7 +156,7 @@ def filter_machine(self, keyword):
qs = qs & Q(cluster_type__in=self.cluster_types)

objs = Machine.objects.filter(qs).prefetch_related(
"storageinstance_set__cluster", "proxyinstance_set__cluster"
"storageinstance_set", "storageinstance_set__cluster", "proxyinstance_set", "proxyinstance_set__cluster"
)

# 解析cluster
Expand All @@ -174,37 +167,41 @@ def filter_machine(self, keyword):
)

# 兼容实例未绑定集群的情况
inst = obj.storageinstance_set.first() or obj.proxyinstance_set.first()
cluster = inst.cluster.first() if inst and inst.cluster.exists() else None
cluster_info = {"cluster_id": None, "cluster_domain": None}
if cluster:
cluster_info.update({"cluster_id": cluster.id, "cluster_domain": cluster.immute_domain})

cluster_info = None
for instances in [obj.storageinstance_set.all(), obj.proxyinstance_set.all()]:
if cluster_info:
break
for inst in instances:
if cluster_info:
break
for cluster in inst.cluster.all():
cluster_info = {"cluster_id": cluster.id, "cluster_dresultomain": cluster.immute_domain}

if cluster_info is None:
cluster_info = {"cluster_id": None, "cluster_domain": None}
machine.update(cluster_info)
machines.append(machine)

return machines

def filter_ticket(self, keyword):
def filter_ticket(self, keyword_list: list):
"""过滤单据,单号为递增数字,采用startswith过滤"""
ticket_ids = [int(keyword) for keyword in keyword_list if isinstance(keyword, int) or keyword.isdigit()]
if not ticket_ids:
return []

try:
ticket_id = int(keyword)
qs = Q(id=ticket_id) if self.filter_type == FilterType.EXACT.value else Q(id__startswith=keyword)
objs = Ticket.objects.filter(qs).order_by("id")
return self.common_filter(
objs,
fields=[
"id",
"creator",
"create_at",
"bk_biz_id",
"ticket_type",
"group",
"status",
"is_reviewed",
],
limit=5,
if self.filter_type == FilterType.EXACT.value:
qs = Q(id__in=ticket_ids)
else:
qs = Q()
for ticket_id in ticket_ids:
qs = qs | Q(id__startswith=ticket_id)

if self.bk_biz_ids:
qs = qs & Q(bk_biz_id__in=self.bk_biz_ids)
objs = Ticket.objects.filter(qs).order_by("id")
return list(
objs[: self.limit].values(
"id", "creator", "create_at", "bk_biz_id", "ticket_type", "group", "status", "is_reviewed"
)
except ValueError:
return []
)
1 change: 1 addition & 0 deletions dbm-ui/backend/db_services/quick_search/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ class QuickSearchSerializer(serializers.Serializer):
)
filter_type = serializers.ChoiceField(help_text=_("检索类型"), choices=FilterType.get_choices(), required=False)
keyword = serializers.CharField(help_text=_("关键字过滤"), required=True, max_length=128)
limit = serializers.IntegerField(help_text=_("分页大小"), required=False, default=10, min_value=1, max_value=1000)
13 changes: 5 additions & 8 deletions dbm-ui/backend/ticket/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
@admin.register(models.Ticket)
class TicketAdmin(admin.ModelAdmin):
list_display = ("id", "bk_biz_id", "ticket_type", "status", "creator", "update_at")
list_filter = ("bk_biz_id", "ticket_type", "status")
list_filter = ("bk_biz_id", "ticket_type", "status", "update_at")
search_fields = ("id", "creator")


@admin.register(models.Flow)
class TicketFlowAdmin(admin.ModelAdmin):
list_display = ("id", "ticket_id", "flow_type", "flow_alias", "flow_obj_id", "status", "update_at")
search_fields = ("flow_obj_id",)
list_filter = ("flow_type", "flow_alias", "status")
search_fields = ("flow_obj_id", "ticket__id")
list_filter = ("flow_type", "flow_alias", "status", "update_at")


@admin.register(models.TicketFlowConfig)
Expand All @@ -37,8 +37,5 @@ class TicketFlowConfigAdmin(admin.ModelAdmin):
@admin.register(models.Todo)
class TodoAdmin(admin.ModelAdmin):
list_display = ("id", "name", "flow_id", "ticket_id", "operators", "type", "done_by", "done_at")
list_filter = (
"type",
"status",
)
search_fields = ("id", "name", "done_by")
list_filter = ("type", "status", "done_at")
search_fields = ("id", "name", "done_by", "ticket__id")
13 changes: 13 additions & 0 deletions dbm-ui/backend/utils/string.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,16 @@ def i18n_str(string):
return ugettext(string)

return string


def split_str_to_list(string: str) -> List[str]:
"""
把逗号、空格、换行符等分割字符串,转为数组
eg: "a,b,c,d" -> ["a", "b", "c", "d"]
:param string: 待分割字符串
"""
string = string.strip()
# 先把逗号、空格、换行符等分割字符串统一替换成 #####
for char in [" ", "\n", "\t", "\r", "\f", "\v"]:
string = string.replace(char, ",")
return string.split(",")
4 changes: 2 additions & 2 deletions helm-charts/bk-dbm/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,5 @@ dependencies:
description: A Helm chart for bk-dbm
name: bk-dbm
type: application
version: 1.3.0-alpha.28
appVersion: 1.3.0-alpha.28
version: 1.3.0-alpha.29
appVersion: 1.3.0-alpha.29
2 changes: 1 addition & 1 deletion helm-charts/bk-dbm/charts/dbconfig/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 0.0.1-alpha.70
appVersion: 0.0.1-alpha.71
description: A Helm chart for dbconfig
name: dbconfig
type: application
Expand Down
2 changes: 1 addition & 1 deletion helm-charts/bk-dbm/charts/dbm/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: 1.3.0-alpha.218
appVersion: 1.3.0-alpha.229
description: A Helm chart for dbm
name: dbm
type: application
Expand Down

0 comments on commit 41d9673

Please sign in to comment.