Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Release History

## 0.9.52 (2026-09-15)

**Feature**

- support auto_text_keys in index creation, updates and responses, with auto_key_detect defaulting to False and auto_text_keys to an empty list. Disabling auto discovery retains the existing auto_text_keys unless explicitly cleared. Updates replace the full auto_text_keys list; preserve existing fields when changing other index settings.

- keys in auto_text_keys are treated as automatically discovered text field indexes with statistical analysis enabled; tokenization and case sensitivity inherit the full-text index settings.

## 0.9.51 (2026-09-07)

**Breaking Changes**
Expand Down
20 changes: 16 additions & 4 deletions aliyun/log/index_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,25 +190,36 @@ class IndexLineConfig(object):
:param chinese: enable Chinese words segmentation

:type auto_key_detect: bool
:param auto_key_detect: enable auto key detection
:param auto_key_detect: enable auto key detection, defaults to False

:type auto_key_count_limit: int
:param auto_key_count_limit: limit for auto key count, only effective when auto_key_detect is True

:type auto_text_keys: string list
:param auto_text_keys: keys treated as automatically discovered text field indexes,
defaults to an empty list. Statistical analysis is enabled for these field
indexes. Tokenization and case sensitivity inherit the full-text (line)
index settings. Disabling auto_key_detect stops discovery of new fields;
existing auto_text_keys remain effective and are retained unless explicitly
cleared. Updates replace the complete list; preserve existing fields when
changing other index settings.

"""

def __init__(self, token_list=None, case_sensitive=False, include_keys=None, exclude_keys=None, chinese=None,
auto_key_detect=None, auto_key_count_limit=None):
auto_key_detect=False, auto_key_count_limit=None, auto_text_keys=None):
if token_list is None:
token_list = []
self.token_list = token_list
self.case_sensitive = case_sensitive
self.chn = bool(chinese)
self.auto_key_detect = auto_key_detect
self.auto_key_count_limit = auto_key_count_limit
self.auto_text_keys = list(auto_text_keys) if auto_text_keys is not None else []

def to_json(self):
json_value = {"token": self.token_list, "caseSensitive": bool(self.case_sensitive)}
json_value = {"token": self.token_list, "caseSensitive": bool(self.case_sensitive),
"auto_text_keys": self.auto_text_keys}
if self.chn is not None:
json_value["chn"] = bool(self.chn)

Expand All @@ -223,7 +234,8 @@ def from_json(self, json_value):
self.token_list = json_value["token"]
self.case_sensitive = bool(json_value.get("caseSensitive", False))
self.chn = bool(json_value["chn"]) if "chn" in json_value else None
self.auto_key_detect = bool(json_value["auto_key_detect"]) if "auto_key_detect" in json_value else None
self.auto_key_detect = bool(json_value.get("auto_key_detect", False))
self.auto_text_keys = list(json_value.get("auto_text_keys") or [])
self.auto_key_count_limit = int(json_value["auto_key_count_limit"]) if "auto_key_count_limit" in json_value else None


Expand Down
4 changes: 3 additions & 1 deletion aliyun/log/index_config.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ class IndexKeyConfig(object):
def from_json(self, json_value: Any) -> None: ...

class IndexLineConfig(object):
def __init__(self, token_list: Optional[List[str]] = ..., case_sensitive: bool = ..., include_keys: Optional[List[str]] = ..., exclude_keys: Optional[List[str]] = ..., chinese: Optional[bool] = ..., auto_key_detect: Optional[bool] = ..., auto_key_count_limit: Optional[int] = ...) -> None: ...
auto_key_detect: Optional[bool]
auto_text_keys: List[str]
def __init__(self, token_list: Optional[List[str]] = ..., case_sensitive: bool = ..., include_keys: Optional[List[str]] = ..., exclude_keys: Optional[List[str]] = ..., chinese: Optional[bool] = ..., auto_key_detect: Optional[bool] = ..., auto_key_count_limit: Optional[int] = ..., auto_text_keys: Optional[List[str]] = ...) -> None: ...
def to_json(self) -> Any: ...
def from_json(self, json_value: Any) -> None: ...

Expand Down
2 changes: 1 addition & 1 deletion aliyun/log/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '0.9.51'
__version__ = '0.9.52'

import sys
OS_VERSION = str(sys.platform)
Expand Down
70 changes: 70 additions & 0 deletions tests/ci/build-test/test_index_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import json

import pytest

from aliyun.log import IndexConfig, IndexLineConfig, LogClient


def test_auto_index_defaults_and_legacy_response():
line = IndexLineConfig()
assert line.auto_key_detect is False
assert line.auto_text_keys == []
assert line.to_json()['auto_key_detect'] is False
assert line.to_json()['auto_text_keys'] == []
line.auto_key_detect = True
line.auto_text_keys.append('host')
assert IndexLineConfig().auto_text_keys == []
line.from_json({'token': [',', ' ']})
assert line.auto_key_detect is False
assert line.auto_text_keys == []


@pytest.mark.parametrize('auto_key_detect', [True, False])
def test_auto_index_create_get_update(monkeypatch, auto_key_detect):
client = LogClient('cn-mock.example.com', 'mock-id', 'mock-key')
requests = []
returned_line = {
'token': [',', ' '], 'caseSensitive': False,
'auto_key_detect': auto_key_detect, 'auto_text_keys': ['host', 'request_id', 'latency'],
}

def send(method, project, body, resource, params, headers):
assert project == 'my-project'
assert resource == '/logstores/my-logs/index'
if method == 'GET':
return {'line': returned_line}, {}
requests.append((method, json.loads(body.decode('utf-8'))))
return {}, {}

monkeypatch.setattr(client, '_send', send)
line = IndexLineConfig(token_list=[',', ' '], auto_key_detect=auto_key_detect,
auto_text_keys=['host', 'request_id', 'latency'])
client.create_index('my-project', 'my-logs', IndexConfig(line_config=line))
config = client.get_index_config('my-project', 'my-logs').get_index_config()
assert config.line_config.auto_key_detect is auto_key_detect
assert config.line_config.auto_text_keys == returned_line['auto_text_keys']
config.line_config.case_sensitive = True
client.update_index('my-project', 'my-logs', config)
config.line_config.auto_text_keys = ['host']
client.update_index('my-project', 'my-logs', config)
config.line_config.auto_text_keys = []
client.update_index('my-project', 'my-logs', config)

assert [method for method, body in requests] == ['POST', 'PUT', 'PUT', 'PUT']
assert all(body['line']['auto_key_detect'] is auto_key_detect for method, body in requests)
assert requests[0][1]['line']['auto_text_keys'] == returned_line['auto_text_keys']
assert requests[1][1]['line']['auto_text_keys'] == returned_line['auto_text_keys']
assert requests[1][1]['line']['caseSensitive'] is True
assert requests[2][1]['line']['auto_text_keys'] == ['host']
assert requests[3][1]['line']['auto_text_keys'] == []


def test_auto_index_preserves_existing_optional_arguments():
line = IndexLineConfig([], False, None, None, False, True, 100, ['host'])
assert line.to_json()['auto_key_count_limit'] == 100
assert line.to_json()['auto_text_keys'] == ['host']
line.auto_key_detect = False
assert 'auto_key_count_limit' not in line.to_json()
assert line.to_json()['auto_text_keys'] == ['host']
line.auto_key_detect = None
assert 'auto_key_detect' not in line.to_json()
Loading