Elasticsearch:Jira 连接器教程第二部分 - 6 个优化技巧
作者:来自 Elastic Gustavo Llermaly
将 Jira 连接到 Elasticsearch 后,我们现在将回顾最佳实践以升级此部署。
在本系列的第一部分中,我们配置了 Jira 连接器并将对象索引到 Elasticsearch 中。在第二部分中,我们将回顾一些最佳实践和高级配置以升级连接器。这些实践是对当前文档的补充,将在索引阶段使用。
运行连接器只是第一步。当你想要索引大量数据时,每个细节都很重要,当你从 Jira 索引文档时,你可以使用许多优化点。
优化点
- 通过应用高级同步过滤器仅索引你需要的文档
- 仅索引你将使用的字段
- 根据你的需求优化映射
- 自动化文档级别安全性
- 卸载附件提取
- 监控连接器的日志
1. 通过应用高级同步过滤器仅索引你需要的文档
默认情况下,Jira 会发送所有项目、问题和附件。如果你只对其中一些感兴趣,或者例如只对 “In Progress - 正在进行” 的问题感兴趣,我们建议不要索引所有内容。
在将文档放入 Elasticsearch 之前,有三个实例可以过滤文档:
- 远程:我们可以使用原生 Jira 过滤器来获取我们需要的内容。这是最好的选择,你应该尽可能尝试使用此选项,因为这样,文档在进入 Elasticsearch 之前甚至不会从源中出来。我们将为此使用高级同步规则。
- 集成:如果源没有原生过滤器来提供我们需要的内容,我们仍然可以使用基本同步规则在集成级别进行过滤,然后再将其导入 Elasticsearch。
- 摄入管道:在索引数据之前处理数据的最后一个选项是使用 Elasticsearch 摄入管道(ingest pipeline)。通过使用 Painless 脚本,我们可以非常灵活地过滤或操作文档。这样做的缺点是数据已经离开源并通过连接器,因此可能会给系统带来沉重的负担并产生安全问题。
让我们快速回顾一下 Jira 问题:
GET bank/_search
{"_source": ["Issue.status.name", "Issue.summary"],"query": {"exists": {"field": "Issue.status.name"}}
}
注意:我们使用 “exists” 查询仅返回具有我们过滤的字段的文档。
你可以看到 “To Do” 中有很多我们不需要的问题:
{"took": 3,"timed_out": false,"_shards": {"total": 2,"successful": 2,"skipped": 0,"failed": 0},"hits": {"total": {"value": 6,"relation": "eq"},"max_score": 1,"hits": [{"_index": "bank","_id": "Marketing Mars-MM-1","_score": 1,"_source": {"Issue": {"summary": "Conquer Mars","status": {"name": "To Do"}}}},{"_index": "bank","_id": "Marketing Mars-MM-3","_score": 1,"_source": {"Issue": {"summary": "Conquering Earth","status": {"name": "In Progress"}}}},{"_index": "bank","_id": "Marketing Mars-MM-2","_score": 1,"_source": {"Issue": {"summary": "Conquer the moon","status": {"name": "To Do"}}}},{"_index": "bank","_id": "Galactic Banking Project-GBP-3","_score": 1,"_source": {"Issue": {"summary": "Intergalactic Security and Compliance","status": {"name": "In Progress"}}}},{"_index": "bank","_id": "Galactic Banking Project-GBP-2","_score": 1,"_source": {"Issue": {"summary": "Bank Application Frontend","status": {"name": "To Do"}}}},{"_index": "bank","_id": "Galactic Banking Project-GBP-1","_score": 1,"_source": {"Issue": {"summary": "Development of API for International Transfers","status": {"name": "To Do"}}}}]}
}
为了仅获取 “In Progress” 的问题,我们将使用 JQL 查询(Jira 查询语言)创建高级同步规则:
转到连接器并单击 sync rules 选项卡,然后单击 Draft Rules。进入后,转到 Advanced Sync Rules 并添加以下内容:
[{"query": "status IN ('In Progress')"}]
应用规则后,运行 Full Content Sync。
此规则将排除所有非 “In Progress” 的问题。你可以通过再次运行查询来检查:
GET bank/_search
{"_source": ["Issue.status.name", "Issue.summary"],"query": {"exists": {"field": "Issue.status.name"}}
}
以下是新的回应:
{"took": 2,"timed_out": false,"_shards": {"total": 2,"successful": 2,"skipped": 0,"failed": 0},"hits": {"total": {"value": 2,"relation": "eq"},"max_score": 1,"hits": [{"_index": "bank","_id": "Marketing Mars-MM-3","_score": 1,"_source": {"Issue": {"summary": "Conquering Earth","status": {"name": "In Progress"}}}},{"_index": "bank","_id": "Galactic Banking Project-GBP-3","_score": 1,"_source": {"Issue": {"summary": "Intergalactic Security and Compliance","status": {"name": "In Progress"}}}}]}
}
2. 仅索引你将使用的字段
现在我们只有我们想要的文档,你可以看到我们仍然会得到很多我们不需要的字段。我们可以在运行查询时使用 _source 隐藏它们,但最好的选择是不索引它们。
为此,我们将使用摄取管道(ingest pipeline)。我们可以创建一个删除所有我们不会使用的字段的管道。假设我们只想要来自问题的以下信息:
- Assignee
- Title
- Status
我们可以创建一个新的摄取管道,仅使用摄取管道的 Content UI 获取这些字段:
单击复 Copy and customize,然后修改名为 index-name@custom 的管道,该管道应该刚刚创建且为空。我们可以使用 Kibana DevTools 控制台执行此操作,运行以下命令:
PUT _ingest/pipeline/bank@custom
{"description": "Only keep needed fields for jira issues and move them to root","processors": [{"remove": {"keep": ["Issue.assignee.displayName","Issue.summary","Issue.status.name"],"ignore_missing": true}},{"rename": {"field": "Issue.assignee.displayName","target_field": "assignee","ignore_missing": true}},{"rename": {"field": "Issue.summary","target_field": "summary","ignore_missing": true}},{"rename": {"field": "Issue.status.name","target_field": "status","ignore_missing": true}},{"remove": {"field": "Issue"}}]
}
让我们删除不需要的字段,并将需要的字段移至文档的根目录。
带有 keep 参数的 remove 处理器将从文档中删除除 keep 数组中的字段之外的所有字段。
我们可以通过运行模拟来检查这是否有效。从索引中添加其中一个文档的内容:
POST /_ingest/pipeline/bank@custom/_simulate
{"docs": [{"_index": "bank","_id": "Galactic Banking Project-GBP-3","_score": 1,"_source": {"Type": "Epic","Custom_Fields": {"Satisfaction": null,"Approvals": null,"Change reason": null,"Epic Link": null,"Actual end": null,"Design": null,"Campaign assets": null,"Story point estimate": null,"Approver groups": null,"[CHART] Date of First Response": null,"Request Type": null,"Campaign goals": null,"Project overview key": null,"Related projects": null,"Campaign type": null,"Impact": null,"Request participants": [],"Locked forms": null,"Time to first response": null,"Work category": null,"Audience": null,"Open forms": null,"Details": null,"Sprint": null,"Stakeholders": null,"Marketing asset type": null,"Submitted forms": null,"Start date": null,"Actual start": null,"Category": null,"Change risk": null,"Target start": null,"Issue color": "purple","Parent Link": {"hasEpicLinkFieldDependency": false,"showField": false,"nonEditableReason": {"reason": "EPIC_LINK_SHOULD_BE_USED","message": "To set an epic as the parent, use the epic link instead"}},"Format": null,"Target end": null,"Approvers": null,"Team": null,"Change type": null,"Satisfaction date": null,"Request language": null,"Amount": null,"Rank": "0|i0001b:","Affected services": null,"Type": null,"Time to resolution": null,"Total forms": null,"[CHART] Time in Status": null,"Organizations": [],"Flagged": null,"Project overview status": null},"Issue": {"statuscategorychangedate": "2024-11-07T16:59:54.786-0300","issuetype": {"avatarId": 10307,"hierarchyLevel": 1,"name": "Epic","self": "https://tomasmurua.atlassian.net/rest/api/2/issuetype/10008","description": "Epics track collections of related bugs, stories, and tasks.","entityId": "f5637521-ec75-48b8-a1b8-de18520807ca","id": "10008","iconUrl": "https://tomasmurua.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10307?size=medium","subtask": false},"components": [],"timespent": null,"timeoriginalestimate": null,"project": {"simplified": true,"avatarUrls": {"48x48": "https://tomasmurua.atlassian.net/rest/api/2/universal_avatar/view/type/project/avatar/10415","24x24": "https://tomasmurua.atlassian.net/rest/api/2/universal_avatar/view/type/project/avatar/10415?size=small","16x16": "https://tomasmurua.atlassian.net/rest/api/2/universal_avatar/view/type/project/avatar/10415?size=xsmall","32x32": "https://tomasmurua.atlassian.net/rest/api/2/universal_avatar/view/type/project/avatar/10415?size=medium"},"name": "Galactic Banking Project","self": "https://tomasmurua.atlassian.net/rest/api/2/project/10001","id": "10001","projectTypeKey": "software","key": "GBP"},"description": null,"fixVersions": [],"aggregatetimespent": null,"resolution": null,"timetracking": {},"security": null,"aggregatetimeestimate": null,"attachment": [],"resolutiondate": null,"workratio": -1,"summary": "Intergalactic Security and Compliance","watches": {"self": "https://tomasmurua.atlassian.net/rest/api/2/issue/GBP-3/watchers","isWatching": true,"watchCount": 1},"issuerestriction": {"issuerestrictions": {},"shouldDisplay": true},"lastViewed": "2024-11-08T02:04:25.247-0300","creator": {"accountId": "712020:88983800-6c97-469a-9451-79c2dd3732b5","emailAddress": "contornan_cliche.0y@icloud.com","avatarUrls": {"48x48": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png","24x24": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png","16x16": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png","32x32": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png"},"displayName": "Tomas Murua","accountType": "atlassian","self": "https://tomasmurua.atlassian.net/rest/api/2/user?accountId=712020%3A88983800-6c97-469a-9451-79c2dd3732b5","active": true,"timeZone": "Chile/Continental"},"subtasks": [],"created": "2024-10-29T15:52:40.306-0300","reporter": {"accountId": "712020:88983800-6c97-469a-9451-79c2dd3732b5","emailAddress": "contornan_cliche.0y@icloud.com","avatarUrls": {"48x48": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png","24x24": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png","16x16": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png","32x32": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png"},"displayName": "Tomas Murua","accountType": "atlassian","self": "https://tomasmurua.atlassian.net/rest/api/2/user?accountId=712020%3A88983800-6c97-469a-9451-79c2dd3732b5","active": true,"timeZone": "Chile/Continental"},"aggregateprogress": {"total": 0,"progress": 0},"priority": {"name": "Medium","self": "https://tomasmurua.atlassian.net/rest/api/2/priority/3","iconUrl": "https://tomasmurua.atlassian.net/images/icons/priorities/medium.svg","id": "3"},"labels": [],"environment": null,"timeestimate": null,"aggregatetimeoriginalestimate": null,"versions": [],"duedate": null,"progress": {"total": 0,"progress": 0},"issuelinks": [],"votes": {"hasVoted": false,"self": "https://tomasmurua.atlassian.net/rest/api/2/issue/GBP-3/votes","votes": 0},"comment": {"total": 0,"comments": [],"maxResults": 0,"self": "https://tomasmurua.atlassian.net/rest/api/2/issue/10008/comment","startAt": 0},"assignee": {"accountId": "712020:88983800-6c97-469a-9451-79c2dd3732b5","emailAddress": "contornan_cliche.0y@icloud.com","avatarUrls": {"48x48": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png","24x24": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png","16x16": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png","32x32": "https://secure.gravatar.com/avatar/f098101294d1a0da282bb2388df8c257?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTM-3.png"},"displayName": "Tomas Murua","accountType": "atlassian","self": "https://tomasmurua.atlassian.net/rest/api/2/user?accountId=712020%3A88983800-6c97-469a-9451-79c2dd3732b5","active": true,"timeZone": "Chile/Continental"},"worklog": {"total": 0,"maxResults": 20,"startAt": 0,"worklogs": []},"updated": "2024-11-07T16:59:54.786-0300","status": {"name": "In Progress","self": "https://tomasmurua.atlassian.net/rest/api/2/status/10004","description": "","iconUrl": "https://tomasmurua.atlassian.net/","id": "10004","statusCategory": {"colorName": "yellow","name": "In Progress","self": "https://tomasmurua.atlassian.net/rest/api/2/statuscategory/4","id": 4,"key": "indeterminate"}}},"id": "Galactic Banking Project-GBP-3","_timestamp": "2024-11-07T16:59:54.786-0300","Key": "GBP-3","_allow_access_control": ["account_id:63c04b092341bff4fff6e0cb","account_id:712020:88983800-6c97-469a-9451-79c2dd3732b5","name:Gustavo","name:Tomas-Murua"]}}]
}
响应将是:
{"docs": [{"doc": {"_index": "bank","_version": "-3","_id": "Galactic Banking Project-GBP-3","_source": {"summary": "Intergalactic Security and Compliance","assignee": "Tomas Murua","status": "In Progress"},"_ingest": {"timestamp": "2024-11-10T06:58:25.494057572Z"}}}]
}
这看起来好多了!现在,让我们运行 full content sync 来应用更改。
3. 根据你的需求优化映射
文档很干净。但是,我们可以进一步优化。我们可以进入 “it depends” 的领域。有些映射可以适用于你的用例,而其他映射则不行。找出答案的最佳方法是进行实验。
假设我们测试并得到了这个映射设计:
- assignee:全文搜索和过滤器
- summary:全文搜索
- status:过滤器和排序
默认情况下,连接器将使用 dynamic_templates 创建映射,这些映射将配置所有文本字段以进行全文搜索、过滤和排序,这是一个坚实的基础,但如果我们知道我们想要用我们的字段做什么,它可以进行优化。
这是规则:
{"all_text_fields": {"match_mapping_type": "string","mapping": {"analyzer": "iq_text_base","fields": {"delimiter": {"analyzer": "iq_text_delimiter","type": "text","index_options": "freqs"},"joined": {"search_analyzer": "q_text_bigram","analyzer": "i_text_bigram","type": "text","index_options": "freqs"},"prefix": {"search_analyzer": "q_prefix","analyzer": "i_prefix","type": "text","index_options": "docs"},"enum": {"ignore_above": 2048,"type": "keyword"},"stem": {"analyzer": "iq_text_stem","type": "text"}}}}
}
让我们为所有文本字段创建用于不同目的的不同子字段。你可以在文档中找到有关分析器的其他信息。
要使用这些映射,你必须:
- 在创建连接器之前创建索引
- 创建连接器时,选择该索引而不是创建新索引
- 创建摄取管道以获取所需的字段
- 运行 Full Content Sync*
*Full Content Sync 会将所有文档发送到 Elasticsearch。Incremental Sync 只会将上次增量或完整内容同步后更改的文档发送到 Elasticsearch。这两种方法都将从数据源获取所有数据。
我们的优化映射如下:
PUT bank-optimal
{"mappings": {"properties": {"assignee": {"type": "text","fields": {"delimiter": {"type": "text","index_options": "freqs","analyzer": "iq_text_delimiter"},"enum": {"type": "keyword","ignore_above": 2048},"joined": {"type": "text","index_options": "freqs","analyzer": "i_text_bigram","search_analyzer": "q_text_bigram"},"prefix": {"type": "text","index_options": "docs","analyzer": "i_prefix","search_analyzer": "q_prefix"},"stem": {"type": "text","analyzer": "iq_text_stem"}},"analyzer": "iq_text_base"},"summary": {"type": "text","fields": {"delimiter": {"type": "text","index_options": "freqs","analyzer": "iq_text_delimiter"},"joined": {"type": "text","index_options": "freqs","analyzer": "i_text_bigram","search_analyzer": "q_text_bigram"},"prefix": {"type": "text","index_options": "docs","analyzer": "i_prefix","search_analyzer": "q_prefix"},"stem": {"type": "text","analyzer": "iq_text_stem"}},"analyzer": "iq_text_base"},"status": {"type": "keyword"}}}
}
对于 assignee,我们保留了原有的映射,因为我们希望此字段针对搜索和过滤器进行优化。对于 summary,我们删除了 “enum” 关键字字段,因为我们不打算过滤摘要。我们将 status 映射为关键字,因为我们只打算过滤该字段。
注意:如果你不确定如何使用字段,基线分析器应该没问题。
4. 自动化文档级安全性
在第一部分中,我们学习了使用文档级安全性 (Document Level Security - DLS) 为用户手动创建 API 密钥并根据该密钥限制访问权限。但是,如果你想在每次用户访问我们的网站时自动创建具有权限的 API 密钥,则需要创建一个脚本来接收请求,使用用户 ID 生成 API 密钥,然后使用它在 Elasticsearch 中搜索。
这是 Python 中的参考文件:
import os
import requests
class ElasticsearchKeyGenerator:def __init__(self):self.es_url = "https://xxxxxxx.es.us-central1.gcp.cloud.es.io" # Your Elasticsearch URLself.es_user = "" # Your Elasticsearch Userself.es_password = "" # Your Elasticsearch password# Basic configuration for requestsself.auth = (self.es_user, self.es_password)self.headers = {'Content-Type': 'application/json'}def create_api_key(self, user_id, index, expiration='1d', metadata=None):"""Create an Elasticsearch API key for a single index with user-specific filters.Args:user_id (str): User identifier on the source systemindex (str): Index nameexpiration (str): Key expiration time (default: '1d')metadata (dict): Additional metadata for the API keyReturns:str: Encoded API key if successful, None if failed"""try:# Get user-specific ACL filtersacl_index = f'.search-acl-filter-{index}'response = requests.get(f'{self.es_url}/{acl_index}/_doc/{user_id}',auth=self.auth,headers=self.headers)response.raise_for_status()# Build the queryquery = {'bool': {'must': [{'term': {'_index': index}},response.json()['_source']['query']]}}# Set default metadata if none providedif not metadata:metadata = {'created_by': 'create-api-key'}# Prepare API key request bodyapi_key_body = {'name': user_id,'expiration': expiration,'role_descriptors': {f'jira-role': {'index': [{'names': [index],'privileges': ['read'],'query': query}]}},'metadata': metadata}print(api_key_body)# Create API keyapi_key_response = requests.post(f'{self.es_url}/_security/api_key',json=api_key_body,auth=self.auth,headers=self.headers)api_key_response.raise_for_status()return api_key_response.json()['encoded']except requests.exceptions.RequestException as e:print(f"Error creating API key: {str(e)}")return None# Example usage
if __name__ == "__main__":key_generator = ElasticsearchKeyGenerator()encoded_key = key_generator.create_api_key(user_id="63c04b092341bff4fff6e0cb", # User id on Jiraindex="bank",expiration="1d",metadata={"application": "my-search-app","namespace": "dev","foo": "bar"})if encoded_key:print(f"Generated API key: {encoded_key}")else:print("Failed to generate API key")
你可以在每个 API 请求上调用此 create_api_key 函数来生成 API 密钥,用户可以在后续请求中使用该密钥查询 Elasticsearch。你可以设置到期时间,还可以设置任意元数据,以防你想要注册有关用户或生成密钥的 API 的一些信息。
5. 卸载附件提取
对于内容提取,例如从 PDF 和 Powerpoint 文件中提取文本,Elastic 提供了一种开箱即用的服务,该服务运行良好,但有大小限制。
默认情况下,本机连接器的提取服务支持每个附件最大 10MB。如果你有更大的附件,例如里面有大图像的 PDF,或者你想要托管提取服务,Elastic 提供了一个工具,可让你部署自己的提取服务。
此选项仅与连接器客户端兼容,因此如果你使用的是本机连接器,则需要将其转换为连接器客户端并将其托管在你自己的基础架构中。
请按照以下步骤操作:
a. 配置自定义提取服务并使用 Docker 运行
docker run \-p 8090:8090 \-it \--name extraction-service \docker.elastic.co/enterprise-search/data-extraction-service:$EXTRACTION_SERVICE_VERSION
EXTRACTION_SERVICE_VERSION 你应该使用 Elasticsearch 8.15 的 0.3.x。
b. 配置 yaml con 提取服务自定义并运行
转到连接器客户端并将以下内容添加到 config.yml 文件以使用提取服务:
extraction_service:host: http://localhost:8090
c. 按照步骤运行连接器客户端
配置完成后,你可以使用要使用的连接器运行连接器客户端。
docker run \
-v "</absolute/path/to>/connectors-config:/config" \ # NOTE: change absolute path to match where config.yml is located on your machine
--tty \
--rm \
docker.elastic.co/enterprise-search/elastic-connectors:{version}.0 \
/app/bin/elastic-ingest \
-c /config/config.yml # Path to your configuration file in the container
你可以参考文档中的完整流程。
6. 监控连接器的日志
在出现问题时,查看连接器的日志非常重要,Elastic 提供了开箱即用的功能。
第一步是在集群中激活日志记录。建议将日志发送到其他集群(监控部署),但在开发环境中,你也可以将日志发送到索引文档的同一集群。
默认情况下,连接器会将日志发送到 elastic-cloud-logs-8 索引。如果你使用的是 Cloud,则可以在新的 Logs Explorer 中检查日志:
结论
在本文中,我们了解了在生产环境中使用连接器时需要考虑的不同策略。优化资源、自动化安全性和集群监控是正确运行大型系统的关键机制。
想要获得 Elastic 认证?了解下一期 Elasticsearch 工程师培训的时间!
Elasticsearch 包含许多新功能,可帮助你为你的用例构建最佳搜索解决方案。深入了解我们的示例笔记本以了解更多信息,开始免费云试用,或立即在你的本地机器上试用 Elastic。
原文:Jira connector tutorial part II: 6 optimization tips - Elasticsearch Labs
相关文章:
Elasticsearch:Jira 连接器教程第二部分 - 6 个优化技巧
作者:来自 Elastic Gustavo Llermaly 将 Jira 连接到 Elasticsearch 后,我们现在将回顾最佳实践以升级此部署。 在本系列的第一部分中,我们配置了 Jira 连接器并将对象索引到 Elasticsearch 中。在第二部分中,我们将回顾一些最佳实…...
单线性激光扫描、多线性激光扫描?激光扫描三维重建算法环节
分类 都属于激光扫描技术,但它们在光源的数量和工作方式上存在一些差异。 单线性激光扫描: 单线性激光扫描使用单个线状光源进行扫描。光源沿一个方向移动,将一条直线上的目标进行扫描。这种方式适用于需要获取目标表面在一个维度上的信息的…...
git 常用命令 git archive
git archive 是 Git 中用于创建一个包含指定提交或分支中所有文件的归档文件(如 .tar 或 .zip)的命令。这个命令非常适合用于分发项目快照、备份代码库或导出特定版本的文件。 git archive --formatzip --outputproject.zip HEAD …...
CMD批处理命令入门(6)——常用的特殊字符
CMD批处理命令入门(6)——特殊字符 本章内容主要学习要点:重定向符 >、>>命令管道符 |组合命令 &、&&、||转义字符 ^变量引导符 %界定符 "" 本章内容主要学习要点: >、>>重定向符| 命令…...
大模型WebUI:Gradio全解11——Chatbot:融合大模型的多模态聊天机器人(6)
大模型WebUI:Gradio全解11——Chatbot:融合大模型的多模态聊天机器人(6) 前言本篇摘要11. Chatbot:融合大模型的多模态聊天机器人11.6 为LLM Agent构建UI11.5.1 使用代理构建1. 使用transformers.agents的实际示例2. 使…...
【算法】前缀和
前缀和 1.【模板】前缀和2.最大子段和3.【模板】二维前缀和4.激光炸弹 前缀的核心思想是预处理,可以在暴力枚举的过程中,快速查询出某一段区间内的和,从而优化时间复杂度。是经典的用空间替换时间的做法。 1.【模板】前缀和 【模板】前缀和…...
android Recyclerview viewholder统一封装
Recyclerview holder 统一封装 ViewHolder类 import android.annotation.SuppressLint import android.content.Context import android.graphics.Color import android.graphics.drawable.GradientDrawable import android.os.Build import android.os.CountDownTimer import…...
【Linux系统】Ext系列磁盘文件系统二:引入文件系统(续篇)
inode 和 block 的映射 该博文中有详细解释:【Linux系统】inode 和 block 的映射原理 目录与文件名 这里有几个问题: 问题一: 我们访问文件,都是用的文件名,没用过 inode 号啊? 之前总是说可以通过一个…...
为AI聊天工具添加一个知识系统 之46 蒙板程序设计(第一版):Facet六边形【意识形态:操纵】
本文要点 要点 (原先标题冒号后只有 “Facet”后改为“Face六边形【意识形态】” ,是 事后想到的,本文并未明确提出。备忘在这里作为后续的“后期制作”的备忘) 前面讨论的(“之41 纯粹的思维”)中 说到,“意识”三…...
Vue.js组件开发-如何处理跨域请求
在Vue.js组件开发中,处理跨域请求(CORS,即跨来源资源共享)通常不是直接在Vue组件中解决的,而是需要后端服务器进行相应的配置,以允许来自不同源的请求。不过,前端开发者也需要了解一些基本的COR…...
unity学习19:unity里用C#脚本获取 gameobject 和 Componenet
目录 1 gameObject 和component 2 gameObject 与C#脚本 2.1 使用 this.gameObject 或gameObject(注意大小写) 2.2 获得其他信息 3 获取其他 GameObject的方法 3.1 获得自身挂载的GameObject 3.2 用find去查找其他的GameObject的名字或tag 3.3 …...
【React】插槽渲染机制
目录 通过 children 属性结合条件渲染通过 children 和 slot 属性实现具名插槽通过 props 实现具名插槽 在 React 中,并没有直接类似于 Vue 中的“插槽”机制(slot)。但是,React 可以通过 props和 children 来实现类似插槽的功能…...
【数据分享】1929-2024年全球站点的逐月平均气温数据(Shp\Excel\免费获取)
气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、湿度等指标,其中又以气温指标最为常用!说到气温数据,最详细的气温数据是具体到气象监测站点的气温数据!本次我们为大家带来的就是具体到气象监…...
立创开发板入门第六课 音频-扬声器和麦克风 I2S驱动
音频芯片介绍 开发板上带有一个麦克风,一个扬声器,音频编解码芯片使用ES8311。麦克风直接连接到了ES8311芯片上,ES8311和扬声器之间,还有一个音频驱动放大器。ES8311通过I2S接口与ESP32-C3连接。 ES8311这个芯片不仅使用I2S接口…...
使用 Java 实现基于 DFA 算法的敏感词检测
使用 Java 实现基于 DFA 算法的敏感词检测 1. 引言 敏感词检测在内容审核、信息过滤等领域有着广泛的应用。本文将介绍如何使用 DFA(Deterministic Finite Automaton,确定有限状态自动机) 算法,在 Java 中实现高效的敏感词检测。…...
springboot集成websocket实现实时大量数据,效率性能高
前言 小编我将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识,有兴趣的小伙伴可以关注一下! 也许一个人独行,可以走的很快,但是一群人结伴而行,才能走的更远!让我们在成长的道路上互相学习&…...
如何在 Google Cloud Shell 中使用 Visual Studio Code (VS Code)?
Google Cloud Shell 是一个基于浏览器的命令行界面,它提供了一个临时的虚拟机环境,允许开发者在没有本地环境配置的情况下使用 Google Cloud 的各种服务。它还提供了一个免费的 5GB 存储空间以及可以在其中执行所有 Google Cloud 操作的命令行界面。 Vis…...
ChatGPT大模型极简应用开发-目录
引言 要理解 ChatGPT,了解其背后的 Transformer 架构和 GPT 技术一路的演进则变得非常必要。 ChatGPT 背后的 LLM 技术使普通人能够通过自然语言完成过去只能由程序员通过编程语言实现的任务,这是一场巨大的变革。然而,人类通常容易高估技术…...
ZooKeeper 核心知识全解析:架构、角色、节点与应用
1.ZooKeeper 分布式锁怎么实现的 ZooKeeper 是一个高效的分布式协调服务,它提供了简单的原语集来构建更复杂的同步原语和协调数据结构。利用 ZooKeeper 实现分布式锁主要依赖于它的顺序节点(Sequential Node)特性以及临时节点(Ep…...
redis实现限流
令牌桶逻辑 计算逻辑: 代码: import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool;/*** ClassName RedisRateLimiterTokenBucket* Description TODO* Author zhang zhengdong* DATE 2025/1/17 20:22* Version 1.0*/ public class…...
云服务器扫描出漏洞怎么办?
随着云计算技术的发展,越来越多的企业和个人选择使用云服务器来托管其应用和服务。然而,安全问题也随之而来。当云服务器的安全扫描显示存在漏洞时,如何正确应对成为了关键。本文将详细介绍发现漏洞后的处理步骤,并提供一些实用的…...
【影刀RPA_启动任务api】
影刀RPA_启动任务api #启动任务api import requests import json from time import sleepyingdao_Info{"accessKeyId":"XXX","accessKeySecret":"XXX","scheduleUuid":XXX,"robotUuid1":"XXX","r…...
Swift语言的多线程编程
Swift语言的多线程编程 在现代软件开发中,多线程编程是提高应用性能和响应速度的重要手段。尤其是在 iOS 和 macOS 开发中,由于用户界面(UI)的交互性和复杂性,合理利用多线程可以极大地提升用户体验。本文将深入探讨 Swift 语言中的多线程编…...
js-判断一个object(对象)是否为空
1.Object.keys() 方法 const obj {};if (Object.keys(obj).length 0) {console.log(Object is empty); } else {console.log(Object is not empty); }Object.keys() 方法返回一个包含对象自身可枚举属性名称的数组。如果这个数组为空,那么对象就是空的。 2.JSO…...
AI在SEO中的关键词优化策略探讨
内容概要 在当今数字化时代,人工智能(AI)正逐渐重塑搜索引擎优化(SEO)行业。AI技术的快速发展使得SEO策略发生了翻天覆地的变化,特别是在关键词优化方面。关键词优化的基本概念是通过选择与用户搜索意图密…...
无缝过渡:将 Ansys 子结构模型转换为 Nastran
了解如何将 Ansys 子结构模型无缝转换为 Nastran,以满足有效载荷动态模型要求 Ansys 子结构模型的优势 Ansys 子结构模型为从事大型装配体结构分析和仿真的工程师和分析师提供了多项优势。 这些模型通过将复杂结构划分为更小、更易于管理的子结构,可以…...
单片机存储器和C程序编译过程
1、 单片机存储器 只读存储器不是并列关系,是从ROM发展到FLASH的过程 RAM ROM 随机存储器 只读存储器 CPU直接存储和访问 只读可访问不可写 临时存数据,存的是CPU正在使用的数据 永久存数据,存的是操作系统启动程序或指令 断电易失 …...
Unity3D实现WEBGL打开Window文件对话框打开/上传文件
系列文章目录 unity工具 文章目录 系列文章目录👉前言👉一、效果展示👉一、unity设置👉1-1、创建Plugins文件夹👉1-2、搭建UI👉二、使用步骤👉2-1、打包webgl👉三、第二种插件实现打开文件对话框👉壁纸分享👉总结👉前言 Unity3D发布的WEBGL程序是不支持…...
探索 Transformer²:大语言模型自适应的新突破
目录 一、来源: 论文链接:https://arxiv.org/pdf/2501.06252 代码链接:SakanaAI/self-adaptive-llms 论文发布时间:2025年1月14日 二、论文概述: 图1 Transformer 概述 图2 训练及推理方法概述 图3 基于提示的…...
SDL2:arm64下编译使用 -- SDL2多媒体库使用音频实例
SDL2:Android-arm64端编译使用 2. SDL2:Android-arm64端编译使用2.1 安装和配置NDK2.2 下载编译SDL22.3 SDL2使用示例:Audio2.4 Android设备运行 2. SDL2:Android-arm64端编译使用 在Linux系统上使用Android NDK编译和使用arm64下…...
Ubuntu、Windows系统网络设置(ping通内外网)
一、 虚拟机VMware和Ubuntu系统的网络配置说明 1、虚拟机的网络适配器的模式有三种: 桥接模式NAT模式主机模式 2、虚拟机VMware的网卡配置(如何进行配置界面(虚拟机->设置)) 注意: 1、以上桥接模式(ubuntu有独立IP)、NAT模式(没有独立IP)都可以联…...
安全类脚本:拒绝ssh暴力破解
要求如下: 一个小时内,连续密码错误4次。 Linux lastb 命令用于列出登入系统失败的用户相关信息。 实验过程如下: 1. 创建两个IP地址不同的干净环境,分别是:192.168.46.101 Rocky 2 和 192.168.46.120 openEuler 2. 2.…...
uc/os-II 原理及应用(八) 系统裁减以及移植到51单片机-下
现在说明几个重要的点, OSStartHighRdy 的作用就是把任务栈复制到系统栈上面,再利用RET的时候会从系统栈上到一个地址放到PC寄存器上来实现任务运行。OSCtxSw是任务切换,把系统栈全部备份到当前任务栈映射上,然后改OSTCBCur,调用…...
关于jwt和security
JSON Web Token(缩写 JWT) 目前最流行、最常见的跨域认证解决方案,前端后端都需要会使用的东西-腾讯云开发者社区-腾讯云 SpringBoot整合Security安全框架、控制权限让我们一起来看看Security吧!我想每个写项目的人,都…...
OpenAI Whisper:语音识别技术的革新者—深入架构与参数
当下语音识别技术正以前所未有的速度发展,极大地推动了人机交互的便利性和效率。OpenAI的Whisper系统无疑是这一领域的佼佼者,它凭借其卓越的性能、广泛的适用性和创新的技术架构,正在重新定义语音转文本技术的规则。今天我们一起了解一下Whi…...
Python 3.9及以上版本支持的新的字符串函数 str.removeprefix()
在 Python 3.9 中,新增了 str.removeprefix() 方法,用于从字符串的开头移除指定的前缀(如果存在)。如果字符串不以指定前缀开头,原字符串保持不变。 用法: str.removeprefix(prefix)prefix: 要移除的前缀…...
Python爬虫入门
豆瓣榜单250爬取: 直接上代码: import requests import redef top250_crawer(url, sum):headers {User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36}try:response re…...
hive连接mysql报错:Unknown version specified for initialization: 3.1.0
分享下一些报错的可能原因吧 1.要开启hadoop 命令:start-all.sh 2.检查 hive-site.xml 和 hive-env.sh。 hive-site.xml中应设置自己mysql的用户名和密码 我的hive-site.xml如下: <configuration><property><name>javax.jdo.opt…...
wandb使用遇到的一些问题
整合了一下使用wandb遇到的问题 1.请问下如果电脑挂了代理,应该怎么办呢?提示:Network error (ProxyError), entering retry loop. 在本地(而非服务器)运行代码时,常常因为开启代理而无法使用wandb&#…...
18. C语言 结构体内存布局分析与优化
本章目录: 结构体的内存布局1. 对齐规则2. 填充与对齐 示例分析代码示例输出结果分析1. debug_size1_t 结构体2. debug_size2_t 结构体 如何优化结构体内存布局1. 成员排序优化2. 使用 #pragma pack 指令注意事项 总结 在C语言中,结构体(structÿ…...
MyBatisPlus学习笔记
To be continue… 文章目录 介绍快速入门入门案例常用注解常用配置 核心功能条件构造器自定义SQLService接口 介绍 MyBatisPlus只做增强不做改变,引入它不会对现有工程产生影响。只需简单配置,即可快速进行单表CRUD操作,从而节省大量时间。…...
Jetpack工具箱:不只是插件,它是开发灵魂
引言 想象一下,一个 Android 开发者面对堆积如山的需求文档、无穷无尽的 BUG 修复时,突然发现了一款神器——Jetpack!这是一套专为 Android 开发者设计的库和工具集,它就像你的“编程助手”,从架构优化到 UI 管理&…...
2024年博客之星年度评选—创作影响力评审入围名单公布
2024年博客之星活动地址https://www.csdn.net/blogstar2024 TOP 300 榜单排名 用户昵称博客主页 身份 认证 评分 原创 博文 评分 平均 质量分评分 互动数据评分 总分排名三掌柜666三掌柜666-CSDN博客1001002001005001wkd_007wkd_007-CSDN博客1001002001005002栗筝ihttps:/…...
LoadBalancer负载均衡服务调用
LoadBalancer LoadBalancer(负载均衡器)是Spring Cloud中的一个关键组件,用于在微服务架构中实现服务请求的负载均衡。它的主要作用是将客户端的请求分发到多个服务实例上,以提高系统的可用性、性能和容错能力。通过LoadBalancer&…...
《CPython Internals》阅读笔记:p221-p231
《CPython Internals》学习第 12天,p221-p231 总结,总计 11 页。 一、技术总结 无。 二、英语总结(生词:2) 1.at a time idiom. separately(单独地) in the specified groups(一次)。示例: (1) I can only do one thing at …...
【机器学习实战入门】基于深度学习的乳腺癌分类
什么是深度学习? 作为对机器学习的一种深入方法,深度学习受到了人类大脑和其生物神经网络的启发。它包括深层神经网络、递归神经网络、卷积神经网络和深度信念网络等架构,这些架构由多层组成,数据必须通过这些层才能最终产生输出。…...
Golang Gin系列-1:Gin 框架总体概述
本文介绍了Gin框架,探索了它的关键特性,并建立了简单入门的应用程序。在这系列教程里,我们会探索Gin的主要特性,如路由、中间件、数据库集成等,最终能使用Gin框架构建健壮的web应用程序。 总体概述 Gin是Go编程语言的…...
【Python】第二弹---深入理解编程基础:从常量、变量到注释的全面解析
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【MySQL】【Python】 目录 1、常量和表达式 2、变量和类型 2.1、变量是什么 2.2、变量的语法 2.3、变量的类型 2.4、动态类型特…...
RPA编程实践:Electron简介
文章目录 前言使用Electron构建桌面应用程序什么是Electron?为什么选择Electron?如何使用Electron实现上述想法?1. 创建基本的Electron应用2. 配置BrowserWindow3. 定制化你的应用4. 打包与分发 前言 Electron,用官网的话说&…...
svn tag
一般发布版本前,需要在svn上打个tag。步骤如下: 1、空白处右击,选择TortoiseSVN->Branch/tag; 2、填写To path,即tag的路基以及tag命名(一般用版本号来命名);填写tag信息;勾选cr…...