Files
opensearch-pyd/test_opensearchpy/test_server/test_helpers/test_faceted_search.py
T
Hugo van Kemenade 6e3f1a1194 Remove redundant mock backport dependency and upgrade syntax for Python 3.8+ (#785)
* Upgrade syntax with pyupgrade --py38-plus

Signed-off-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>

* Convert to f-strings with flynt

Signed-off-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>

* Format with Black

Signed-off-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>

* Remove redundant mock backport dependency

Signed-off-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>

* isort imports

Signed-off-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>

* Add changelog entry

Signed-off-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>

---------

Signed-off-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
2024-07-20 16:19:20 -04:00

291 lines
8.7 KiB
Python

# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#
# Modifications Copyright OpenSearch Contributors. See
# GitHub history for details.
#
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from datetime import datetime
from typing import Any
import pytest
from opensearchpy import A, Boolean, Date, Document, Keyword
from opensearchpy.helpers.faceted_search import (
DateHistogramFacet,
FacetedSearch,
NestedFacet,
RangeFacet,
TermsFacet,
)
from .test_document import PullRequest
class Repos(Document):
is_public = Boolean()
created_at = Date()
class Index:
name = "git"
class Commit(Document):
files = Keyword()
committed_date = Date()
class Index:
name = "git"
class MetricSearch(FacetedSearch):
index = "git"
doc_types = [Commit]
facets = {
"files": TermsFacet(field="files", metric=A("max", field="committed_date")),
}
@pytest.fixture(scope="session") # type: ignore
def commit_search_cls(opensearch_version: Any) -> Any:
interval_kwargs = {"fixed_interval": "1d"}
class CommitSearch(FacetedSearch):
index = "flat-git"
fields = (
"description",
"files",
)
facets = {
"files": TermsFacet(field="files"),
"frequency": DateHistogramFacet(
field="authored_date", min_doc_count=1, **interval_kwargs
),
"deletions": RangeFacet(
field="stats.deletions",
ranges=[("ok", (None, 1)), ("good", (1, 5)), ("better", (5, None))],
),
}
return CommitSearch
@pytest.fixture(scope="session") # type: ignore
def repo_search_cls(opensearch_version: Any) -> Any:
interval_type = "calendar_interval"
class RepoSearch(FacetedSearch):
index = "git"
doc_types = [Repos]
facets = {
"public": TermsFacet(field="is_public"),
"created": DateHistogramFacet(
field="created_at", **{interval_type: "month"}
),
}
def search(self) -> Any:
s = super().search()
return s.filter("term", commit_repo="repo")
return RepoSearch
@pytest.fixture(scope="session") # type: ignore
def pr_search_cls(opensearch_version: Any) -> Any:
interval_type = "calendar_interval"
class PRSearch(FacetedSearch):
index = "test-prs"
doc_types = [PullRequest]
facets = {
"comments": NestedFacet(
"comments",
DateHistogramFacet(
field="comments.created_at", **{interval_type: "month"}
),
)
}
return PRSearch
def test_facet_with_custom_metric(data_client: Any) -> None:
ms = MetricSearch()
r = ms.execute()
dates = [f[1] for f in r.facets.files]
assert dates == list(sorted(dates, reverse=True))
assert dates[0] == 1399038439000
def test_nested_facet(pull_request: Any, pr_search_cls: Any) -> None:
prs = pr_search_cls()
r = prs.execute()
assert r.hits.total.value == 1
assert [(datetime(2018, 1, 1, 0, 0), 1, False)] == r.facets.comments
def test_nested_facet_with_filter(pull_request: Any, pr_search_cls: Any) -> None:
prs = pr_search_cls(filters={"comments": datetime(2018, 1, 1, 0, 0)})
r = prs.execute()
assert r.hits.total.value == 1
assert [(datetime(2018, 1, 1, 0, 0), 1, True)] == r.facets.comments
prs = pr_search_cls(filters={"comments": datetime(2018, 2, 1, 0, 0)})
r = prs.execute()
assert not r.hits
def test_datehistogram_facet(data_client: Any, repo_search_cls: Any) -> None:
rs = repo_search_cls()
r = rs.execute()
assert r.hits.total.value == 1
assert [(datetime(2014, 3, 1, 0, 0), 1, False)] == r.facets.created
def test_boolean_facet(data_client: Any, repo_search_cls: Any) -> None:
rs = repo_search_cls()
r = rs.execute()
assert r.hits.total.value == 1
assert [(True, 1, False)] == r.facets.public
value, count, selected = r.facets.public[0]
assert value is True
assert count == 1
assert selected is False
def test_empty_search_finds_everything(
data_client: Any, opensearch_version: Any, commit_search_cls: Any
) -> None:
cs = commit_search_cls()
r = cs.execute()
assert r.hits.total.value == 52
assert [
("opensearchpy", 39, False),
("test_opensearchpy", 35, False),
("test_opensearchpy/test_dsl", 35, False),
("opensearchpy/query.py", 18, False),
("test_opensearchpy/test_dsl/test_search.py", 15, False),
("opensearchpy/utils.py", 14, False),
("test_opensearchpy/test_dsl/test_query.py", 13, False),
("opensearchpy/search.py", 12, False),
("opensearchpy/aggs.py", 11, False),
("test_opensearchpy/test_dsl/test_result.py", 5, False),
] == r.facets.files
assert [
(datetime(2014, 3, 3, 0, 0), 2, False),
(datetime(2014, 3, 4, 0, 0), 1, False),
(datetime(2014, 3, 5, 0, 0), 3, False),
(datetime(2014, 3, 6, 0, 0), 3, False),
(datetime(2014, 3, 7, 0, 0), 9, False),
(datetime(2014, 3, 10, 0, 0), 2, False),
(datetime(2014, 3, 15, 0, 0), 4, False),
(datetime(2014, 3, 21, 0, 0), 2, False),
(datetime(2014, 3, 23, 0, 0), 2, False),
(datetime(2014, 3, 24, 0, 0), 10, False),
(datetime(2014, 4, 20, 0, 0), 2, False),
(datetime(2014, 4, 22, 0, 0), 2, False),
(datetime(2014, 4, 25, 0, 0), 3, False),
(datetime(2014, 4, 26, 0, 0), 2, False),
(datetime(2014, 4, 27, 0, 0), 2, False),
(datetime(2014, 5, 1, 0, 0), 2, False),
(datetime(2014, 5, 2, 0, 0), 1, False),
] == r.facets.frequency
assert [
("ok", 19, False),
("good", 14, False),
("better", 19, False),
] == r.facets.deletions
def test_term_filters_are_shown_as_selected_and_data_is_filtered(
data_client: Any, commit_search_cls: Any
) -> None:
cs = commit_search_cls(filters={"files": "test_opensearchpy/test_dsl"})
r = cs.execute()
assert 35 == r.hits.total.value
assert [
("opensearchpy", 39, False),
("test_opensearchpy", 35, False),
("test_opensearchpy/test_dsl", 35, True),
("opensearchpy/query.py", 18, False),
("test_opensearchpy/test_dsl/test_search.py", 15, False),
("opensearchpy/utils.py", 14, False),
("test_opensearchpy/test_dsl/test_query.py", 13, False),
("opensearchpy/search.py", 12, False),
("opensearchpy/aggs.py", 11, False),
("test_opensearchpy/test_dsl/test_result.py", 5, False),
] == r.facets.files
assert [
(datetime(2014, 3, 3, 0, 0), 1, False),
(datetime(2014, 3, 5, 0, 0), 2, False),
(datetime(2014, 3, 6, 0, 0), 3, False),
(datetime(2014, 3, 7, 0, 0), 6, False),
(datetime(2014, 3, 10, 0, 0), 1, False),
(datetime(2014, 3, 15, 0, 0), 3, False),
(datetime(2014, 3, 21, 0, 0), 2, False),
(datetime(2014, 3, 23, 0, 0), 1, False),
(datetime(2014, 3, 24, 0, 0), 7, False),
(datetime(2014, 4, 20, 0, 0), 1, False),
(datetime(2014, 4, 25, 0, 0), 3, False),
(datetime(2014, 4, 26, 0, 0), 2, False),
(datetime(2014, 4, 27, 0, 0), 1, False),
(datetime(2014, 5, 1, 0, 0), 1, False),
(datetime(2014, 5, 2, 0, 0), 1, False),
] == r.facets.frequency
assert [
("ok", 12, False),
("good", 10, False),
("better", 13, False),
] == r.facets.deletions
def test_range_filters_are_shown_as_selected_and_data_is_filtered(
data_client: Any, commit_search_cls: Any
) -> None:
cs = commit_search_cls(filters={"deletions": "better"})
r = cs.execute()
assert 19 == r.hits.total.value
def test_pagination(data_client: Any, commit_search_cls: Any) -> None:
cs = commit_search_cls()
cs = cs[0:20]
assert 52 == cs.count()
assert 20 == len(cs.execute())