基于图的去中心化社会推荐过滤器

🏡作者主页:点击! 

🤖编程探索专栏:点击!

⏰️创作时间:2024年11月11日19点20分

点击开启你的论文编程之旅icon-default.png?t=O83Ahttps://www.aspiringcode.com/content?id=17176636216843&uid=eba758a1550b46bb94314cb8eeea8c3f

原论文研究背景与研究意义概述


这篇论文由中国科学技术大学团队于2023年发表在TKDE期刊上,主要研究领域是基于用户-用户和用户-事件社会关系的推荐生成。由于这些社会关系可以轻松地用图结构数据来表示,因此图神经网络在这一领域具有很大的发展潜力。然而,现有的基于图的算法在处理数据时往往忽略了用户或事件的偏好偏移量。作者给出的一个示例说明了这种偏移量的重要性:挑剔的用户给出的低评分并不一定意味着他们对产品的态度是消极的,因为这些用户通常会给出低评分,这可能会导致图结构数据分析产生误差。现有的方法通常将这种偏差作为标量融入模型训练中,但作者认为这种做法不足以捕捉所有相关信息。此外,作者指出,用户之间的社会联系也应被考虑在内,因为具有相似偏好的用户往往会对彼此产生更大的影响。基于此,作者提出了一种新的算法来解决这些问题。

论文所提出算法的主要贡献

这篇文章的主要贡献包括:
首先,作者将评价偏移量处理为向量,并将其融入到用户和事件的表征学习中。具体做法是计算用户与其他用户的评价差异向量,从而获得每个用户的评价偏移。具体做法是,他们对原始图进行去中心化处理,然后从中学习到用户和事件的表征。去中心化的图是基于原始图中的统计信息生成的。

接着,作者提出了一种用户-用户之间社会关系的建模方式,并将其融入到预测规则中,以提高推荐表现。

然后,基于去中心化图,他们提出了一种基于图神经网络(GNN)的社会推荐协同过滤模型。

最后,作者在两个数据集上验证了所提出算法的有效性,证明了其在处理用户偏好偏移量和社会关系建模方面的优势。

原论文中采用了大量的数学公式来表示算法过程,这里笔者认为实际上读起来有点费力,所以本文主要从感性的角度来对这篇论文进行讲解,尽量少用公式而是用文字描述来给大家建立一个感性的理解。

GDSRec算法原理与流程


问题定义


原文采用的建图方式是将用户和事件作为节点,用户-事件之间的连线权重为关系系数Tij,用于衡量两个用户的相似度。

关系系数的计算方式可以看作是设定一个阈值,当两个用户对同一个事件的评分差距在阈值之内时,就将相似度加一,累加起来就是两个用户的相似度,这里称为关系系数。而用户-事件连线的权重为用户对事件的评分。然而,作者指出,直接使用这种原始图会带来一些不足,也就是无法准确反映真正的用户偏好。这是因为用户对事件的评分可能受到不同用户的打分标准的影响,从而导致误解用户的真实偏好。因此,作者对图结构进行了去中心化处理,以更好地捕捉用户的真实偏好。

去中心化图(decentralized graph)


去中心化图有三种不同的边:用户-事件、事件-用户、用户-用户。对于每个用户-事件交互的边,用原始权重减去所有权重的平均值得到新的权重,而用户-用户连线的权重保持不变。通过这种方式,作者将统计信息融入到图中。接下来,作者针对这种去中心化图进行了对用户、事件、社会联系三种方向的建模,从而计算出三种潜在因素偏移量。依据这些偏移量,可以计算出最终用户ui和事件vj的最终偏好评分,即:

所提出方法(三种并行建模)

用户建模(user modelling)

然后我们具体介绍一下作者提出的三种建模方式。我们以用户建模(user modeling)为例,期望得到的输出是潜在因素偏移量hui。整个流程可以用上面的公式表示,我们可以逐步拆分这个过程。

首先,需要提到的是,在这个过程中使用的用户-事件交互权重都是进行取整后的。原文指出,使用小数进行embedding不太方便,但同时也提到一些量化方法可以解决这个问题,他们将这部分留作未来工作。前面提到,这篇文章的一大贡献是将评价偏移量处理为向量。

具体做法是将事件𝑣𝑙vl

用户-事件交互的权重进行embedding后的表征进行拼接,然后通过一个多层感知机进行处理,从而融入到学习过程中。𝑞,𝑠qs分别是事件𝑢u和社会关联𝑟r的表征,𝐿𝑈LU是多层感知机,这种方法可以将该向量融入用户表征的学习过程中

同时,作者指出,一个用户和相关联事件之间的每个关联对用户潜在因素的影响贡献是不同的。因此,他们采用了注意力机制来捕捉用户偏好中的差异。公式8中𝑥x前面乘的系数实际上是注意力权重。需要注意的是,在输入注意力网络时,他们将前面的评价偏移向量与用户的embedding向量进行了拼接,然后通过一个两层神经网络进行处理。通过这一流程,就可以得到用户的潜在因素偏移量hui。

事件建模(item modeling)和社会关系建模(social modeling)的处理方式与用户建模类似。三种建模处理后,我们可以得到三种潜在因素偏移量。基于此,偏好评分可以通过三层神经网络获得,用公式9,10,11表示。这个偏好评分可以理解为包括用户自己的意见和对其社会关联用户评级的参考。对于用户ui的社会关联用户,我们可以用相同的方式得到他们的偏好评分,从而得到方程f的返回值,计算方式如公式12。

最终,我们回到前面公式4就可以计算出用户ui和事件vj之间的最终评分。以这种方式就可以实现对用户更全面偏好信息的捕获,以及考虑到有着更强社会关联的用户对用户ui的影响。

模版代码讲解


main.py顶层文件:用于集成模与函数功能

main.py文件在这里仍然是起到一个调用模型和所有函数进行数据输入、处理、训练、结果输出的功能,值得注意的是这里原文作者使用了config参数定义的方式,让整个工程看起来更加简洁、标准

import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'
import pickle
import torch
from torch.utils.data import DataLoader
from utils import collate_fn
from model.GDSRec_model import GDSRec_Engine


config = {
    'model': 'GDSRec', 
    'dataset': 'Ciao',  # Ciao/Epinions
    'optimizer': 'adam',
    'l2_regularization': 0.01,
    'embed_size': 64,
    'batch_size': 128,
    'layers': [256,128,128,64,64],
    'epoch': 20,
    'lr': 0.0005,  # 0.01, 0.001, 0.0001
    'lr_dc': 0.1,  # learning rate decay
    'lr_dc_step': 100,  # the number steps for decay
    'test':False,
    'model_dir': 'checkpoints/{}_{}_best_checkpoint.model'
}
print(config)
here = os.path.dirname(os.path.abspath(__file__))
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
config['device'] = device
workdir = 'C:/Users/meicr/Desktop/GDSRec_rank/data/'
with open(workdir + config['dataset'] + '/' + config['model'] + '_dataset.pkl', 'rb') as f:
    train_dataset, evaluate_dataset, test_dataset, user_count, item_count = pickle.loads(f.read())
config['num_users'] = user_count
config['num_items'] = item_count
config['num_rates'] = 5

if config['test'] is False:
    engine = GDSRec_Engine(config)
    train_loader = DataLoader(train_dataset, batch_size=config['batch_size'], shuffle=True, collate_fn=collate_fn)
    evaluate_loader = DataLoader(evaluate_dataset, batch_size=config['batch_size'], shuffle=False,
                                    collate_fn=collate_fn)
    index_sum = []
    for epoch in range(config['epoch']):
        print('Epoch {} starts !'.format(epoch))
        engine.train_an_epoch(train_loader, epoch)
        recall, ndcg = engine.evaluate(evaluate_loader, epoch)
        if epoch == 0:
            pre_sum = recall + ndcg
            index_sum.append(0)
        else:
            if recall + ndcg < pre_sum:
                index_sum.append(1)
            else:
                pre_sum = recall + ndcg
                index_sum.append(0)
        if sum(index_sum[-10:]) == 10:
            break
        if epoch == 0:
            best_sum = recall + ndcg
            engine.save()
        elif recall + ndcg > best_sum:
            best_sum = recall + ndcg
            engine.save()
else:
    engine = GDSRec_Engine(config)
    print('Load checkpoint and testing...')
    engine.resume()
    test_loader = DataLoader(test_dataset, batch_size=config['batch_size'], shuffle=True, collate_fn=collate_fn)
    recall, ndcg = engine.evaluate(test_loader, epoch_id=0)

preprocess.py:对输入数据进行预处理符合模型输入要求


这里preprocess.py文件的作用是对我们输入的数据进行了处理和分析得到模型可以处理的对象,主要包括格式转换、用户相似度计算之类的功能

"""
@author: Jiajia Chan
@date: 20 June, 2020
"""
import random
import argparse
import pickle
import pandas as pd
from scipy.io import loadmat
from rating_data import SingleGenerator
from trust_data import SocialGenerator

random.seed(1234)


if __name__ == '__main__':
    parser = argparse.ArgumentParser() 
    parser.add_argument('--dataset', default='Ciao', help='dataset name: Ciao/Epinions')
    parser.add_argument('--test_prop', default=0.2, help='the proportion of data used for test')
    args = parser.parse_args() 
    workdir = 'data/'

    click_f = loadmat(workdir + args.dataset + '/rating.mat')['rating']
    trust_f = loadmat(workdir + args.dataset + '/trustnetwork.mat')['trustnetwork']
    click_dt = pd.DataFrame(click_f)
    trust_dt = pd.DataFrame(trust_f, columns=['userID', 'freID'])
    click_dt = click_dt[[0, 1, 3]]
    click_dt.dropna(inplace=True)
    click_dt.drop_duplicates(inplace=True)
    click_dt.columns = ['userID', 'itemID', 'rating']
    trust_dt.dropna(inplace=True)
    trust_dt.drop_duplicates(inplace=True)

    single_generator = SingleGenerator(ratings=click_dt, prob=args.test_prop)
    social_generator = SocialGenerator(singlegenerator=single_generator, trust=trust_dt)
    GDSRec_dataset = social_generator.instance_GDSRec_dataset()
    general_dataset = single_generator.instance_general_dataset()
    with open(workdir + args.dataset +'/' + 'GDSRec' + '_dataset.pkl', 'wb') as f:
        str1 = pickle.dumps(GDSRec_dataset)
        f.write(str1)
        f.close()

model.py:GDSRec模型实现


这个文件里面存放的就是所提出方法和相关算法的所有实现,原理和流程就如上述介绍所示

from torch import nn
from torch.nn import init
import torch
import numpy as np

class _MultiLayerPercep(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(_MultiLayerPercep, self).__init__()
        self.mlp = nn.Sequential(
            nn.Linear(input_dim, input_dim // 2, bias=True),
            nn.ReLU(),
            nn.Linear(input_dim // 2, output_dim, bias=True),
        )

    def forward(self, x):
       return self.mlp(x)


class _MultiLayerPercep_tanh(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(_MultiLayerPercep_tanh, self).__init__()
        self.mlp = nn.Sequential(
            nn.Linear(input_dim, input_dim // 2, bias=True),
            nn.Tanh(),
            nn.Linear(input_dim // 2, output_dim, bias=True),
        )

    def forward(self, x):
       return self.mlp(x)


class _Aggregation(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(_Aggregation, self).__init__()
        self.aggre = nn.Sequential(
            nn.Linear(input_dim, output_dim, bias=True),
            nn.Tanh(),
        )

    def forward(self, x):
        return self.aggre(x)


class _UserModel(nn.Module):
    ''' User modeling to learn user latent factors.
    User modeling leverages two types aggregation: item aggregation and social aggregation
    '''

    def __init__(self, emb_dim, user_emb, item_emb, rate_emb):
        super(_UserModel, self).__init__()
        self.user_emb = user_emb
        self.item_emb = item_emb
        self.rate_emb = rate_emb
        self.emb_dim = emb_dim

        self.g_v = _MultiLayerPercep_tanh(2 * self.emb_dim, self.emb_dim)

        self.user_items_att = _MultiLayerPercep(2 * self.emb_dim, 1)
        self.aggre_items = _Aggregation(self.emb_dim, self.emb_dim)


        self.combine_mlp = nn.Sequential(
            nn.Linear(2 * self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
        )

        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        # used for preventing zero div error when calculating softmax score
        self.eps = 1e-10

    def forward(self, uids, u_item_pad):
        # item aggregation
        q_a = self.item_emb(u_item_pad[:, :, 0])  
        mask_u = torch.where(u_item_pad[:, :, 0] > 0, torch.tensor([1.], device=self.device),
                             torch.tensor([0.], device=self.device))  
        u_item_er = self.rate_emb(u_item_pad[:, :, 1])  

        x_ia = self.g_v(torch.cat([q_a, u_item_er], dim=2).view(-1, 2 * self.emb_dim)).view(
            q_a.size())  

        ## calculate attention scores in item aggregation
        p_i = mask_u.unsqueeze(2).expand_as(x_ia) * self.user_emb(uids).unsqueeze(1).expand_as(
            x_ia)  
        alpha = self.user_items_att(torch.cat([x_ia, p_i], dim=2).view(-1, 2 * self.emb_dim)).view(
            mask_u.size())  # B x maxi_len
        alpha = torch.exp(alpha) * mask_u
        alpha = alpha / (torch.sum(alpha, 1).unsqueeze(1).expand_as(alpha) + self.eps)

        h_iI = self.aggre_items(torch.sum(alpha.unsqueeze(2).expand_as(x_ia) * x_ia, 1))  # B x emb_dim

        return h_iI


class _ItemModel(nn.Module):
    '''Item modeling to learn item latent factors.
    '''

    def __init__(self, emb_dim, user_emb, item_emb, rate_emb):
        super(_ItemModel, self).__init__()
        self.emb_dim = emb_dim
        self.user_emb = user_emb
        self.item_emb = item_emb
        self.rate_emb = rate_emb

        self.g_u = _MultiLayerPercep_tanh(2 * self.emb_dim, self.emb_dim)

        self.item_users_att = _MultiLayerPercep(2 * self.emb_dim, 1)
        self.aggre_users = _Aggregation(self.emb_dim, self.emb_dim)

        self.combine_mlp = nn.Sequential(
            nn.Linear(2 * self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
        )

        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        self.eps = 1e-10

    def forward(self, iids, i_user_pad):
        # user aggregation
        p_t = self.user_emb(i_user_pad[:, :, 0])
        mask_i = torch.where(i_user_pad[:, :, 0] > 0, torch.tensor([1.], device=self.device),
                             torch.tensor([0.], device=self.device))
        i_user_er = self.rate_emb(i_user_pad[:, :, 1])

        f_jt = self.g_u(torch.cat([p_t, i_user_er], dim=2).view(-1, 2 * self.emb_dim)).view(p_t.size())

        # calculate attention scores in user aggregation
        q_j = mask_i.unsqueeze(2).expand_as(f_jt) * self.item_emb(iids).unsqueeze(1).expand_as(f_jt)

        miu = self.item_users_att(torch.cat([f_jt, q_j], dim=2).view(-1, 2 * self.emb_dim)).view(mask_i.size())
        miu = torch.exp(miu) * mask_i
        miu = miu / (torch.sum(miu, 1).unsqueeze(1).expand_as(miu) + self.eps)

        z_jU = self.aggre_users(torch.sum(miu.unsqueeze(2).expand_as(f_jt) * f_jt, 1))

        return z_jU


class _SocialModel(nn.Module):
    '''
    socialmodel to learn the rating for specific user exploiting social related users
    '''
    def __init__(self, emb_dim, user_emb, item_emb, rate_emb, sim_emb):
        super(_SocialModel, self).__init__()
        self.emb_dim = emb_dim
        self.user_emb = user_emb
        self.item_emb = item_emb
        self.rate_emb = rate_emb
        self.sim_emb = sim_emb
        self.g_v = _MultiLayerPercep_tanh(2 * self.emb_dim, self.emb_dim)

        self.user_items_att = _MultiLayerPercep(2 * self.emb_dim, 1)
        self.user_users_att = _MultiLayerPercep(2 * self.emb_dim, 1)
        self.aggre_items = _Aggregation(self.emb_dim, self.emb_dim)

        self.combine_mlp = nn.Sequential(
            nn.Linear(2 * self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
        )
        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        self.eps = 1e-10

    def forward(self, u_user_pad, u_user_item_pad):
        q_a_s = self.item_emb(u_user_item_pad[:, :, :, 0])  
        mask_s = torch.where(u_user_item_pad[:, :, :, 0] > 0, torch.tensor([1.], device=self.device),
                             torch.tensor([0.], device=self.device)) 
        u_user_item_er = self.rate_emb(u_user_item_pad[:, :, :, 1]) 

        x_ia_s = self.g_v(torch.cat([q_a_s, u_user_item_er], dim=3).view(-1, 2 * self.emb_dim)).view(
            q_a_s.size())  

        p_i_s = mask_s.unsqueeze(3).expand_as(x_ia_s) * self.user_emb(u_user_pad[:, :, 0]).unsqueeze(2).expand_as(
            x_ia_s)  

        alpha_s = self.user_items_att(torch.cat([x_ia_s, p_i_s], dim=3).view(-1, 2 * self.emb_dim)).view(
            mask_s.size())  
        alpha_s = torch.exp(alpha_s) * mask_s
        alpha_s = alpha_s / (torch.sum(alpha_s, 2).unsqueeze(2).expand_as(alpha_s) + self.eps)

        h_oI_temp = torch.sum(alpha_s.unsqueeze(3).expand_as(x_ia_s) * x_ia_s, 2) 
        h_oI = self.aggre_items(h_oI_temp.view(-1, self.emb_dim)).view(h_oI_temp.size())  

        return h_oI


class GDSRec(nn.Module):
    '''

    Args:
        number_users: the number of users in the dataset.
        number_items: the number of items in the dataset.
        num_rate_levels: the number of rate levels in the dataset.
        emb_dim: the dimension of user and item embedding (default = 64).

    '''

    def __init__(self, num_users, num_items, num_rate_levels, emb_dim=64):
        super(GDSRec, self).__init__()
        self.num_users = num_users
        self.num_items = num_items
        self.num_rate_levels = num_rate_levels
        self.emb_dim = emb_dim
        self.user_emb = nn.Embedding(self.num_users, self.emb_dim, padding_idx=0)
        self.item_emb = nn.Embedding(self.num_items, self.emb_dim, padding_idx=0)
        self.rate_emb = nn.Embedding(self.num_rate_levels, self.emb_dim, padding_idx=0)
        self.sim_dim = nn.Embedding(self.num_items, self.emb_dim, padding_idx=0)
        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
        self.eps = 1e-10
        self.user_model = _UserModel(self.emb_dim, self.user_emb, self.item_emb, self.rate_emb)

        self.item_model = _ItemModel(self.emb_dim, self.user_emb, self.item_emb, self.rate_emb)

        self.social_model = _SocialModel(self.emb_dim, self.user_emb, self.item_emb, self.rate_emb, self.sim_dim)

        self.rate_pred = nn.Sequential(
            nn.Linear(2 * self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, self.emb_dim, bias=True),
            nn.Tanh(),
            nn.Linear(self.emb_dim, 1),
        )

    def forward(self, uids, iids, u_itemdiv_pad, u_avgs, u_user_pad, u_user_item_pad, i_user_pad, i_avgs):
        '''
        Args:
            uids: the user id sequences.
            iids: the item id sequences.
            u_itemdiv_pad: the padded user-item-div graph
            u_item_pad: the padded user-item graph.
            u_avgs: the avg rating of user
            u_user_pad: the padded user-user graph.
            u_user_item_pad: the padded user-user-item graph.
            i_user_pad: the padded item-user graph.
            i_avgs: the avg rating of item
        Shapes:
            uids: (B).
            iids: (B).
            u_item_pad: (B, ItemSeqMaxLen, 2).
            u_avgs: (B)
            u_user_pad: (B, UserSeqMaxLen).
            u_user_item_pad: (B, UserSeqMaxLen, truncate_len, 2).
            i_user_pad: (B, UserSeqMaxLen, 2).
            i_avgs: (B)
        Returns:
            the predicted rate scores of the user to the item.
        '''

        h_i = self.user_model(uids, u_itemdiv_pad)  
        z_j = self.item_model(iids, i_user_pad) 
        y_i = self.social_model(u_user_pad, u_user_item_pad) 
        mask = u_user_pad[:, :, 1].unsqueeze(2).float() 

        # make prediction
        r_ij_1 = self.rate_pred(torch.cat([h_i, z_j], dim=1))
        r_ij_2 = torch.sum(self.rate_pred(torch.cat([y_i, z_j.unsqueeze(1).expand_as(y_i)], dim=2)) * mask, dim=1)\
                 /(torch.sum(mask, dim=1) + self.eps)
        r_ij = 0.5 *(r_ij_1 + r_ij_2) + 0.5*(u_avgs.unsqueeze(1) + i_avgs.unsqueeze(1))

        return r_ij

本地部署方法


我们在github官方链接上只能找到一个数据集Ciao(原论文是在Ciao和Epinions上都进行了实验),我们需要将数据集整理成上述格式,这里可以打开看一下。整理的格式如右图所示,第一列是学生id, 第二列是问题id,第三列是无关变量原文代码中并没有用到,第四列是rating,trustnetwork.mat文件中保存的是学生与学生之间的关系网络。因此我们在进行本地私有数据集训练时也需要将数据处理成对应的格式

该篇论文作者在github上公布了源代码,但笔者下载下来实际运行了之后发现完全按照模版代码运行仍然会出现一些问题。研究之后发现可能是原作者在编写代码后改动了数据集目录格式,导致一些设定的环境路径参数错误。如果我们想要跑通代码或者在本地运行自己的数据集进行实验,还需要对相应的参数进行修改,修改后的代码我已经放在本文附件中了,并且在附件的压缩包内新增了一个Readme文件来提示大家如何修改数据集路径为自己的私有数据集

成功的路上没有捷径,只有不断的努力与坚持。如果你和我一样,坚信努力会带来回报,请关注我,点个赞,一起迎接更加美好的明天!你的支持是我继续前行的动力!"

"每一次创作都是一次学习的过程,文章中若有不足之处,还请大家多多包容。你的关注和点赞是对我最大的支持,也欢迎大家提出宝贵的意见和建议,让我不断进步。"

神秘泣男子

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/913649.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云计算在教育领域的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 云计算在教育领域的应用 云计算在教育领域的应用 云计算在教育领域的应用 引言 云计算概述 定义与原理 发展历程 云计算的关键技…

开始使用 Elastic AI Assistant 进行可观察性和 Microsoft Azure OpenAI

作者&#xff1a;Jonathan Simon 按照此分步过程开始使用 Elastic AI Assistant for Observability 和 Microsoft Azure OpenAI。 最近&#xff0c;Elastic 宣布&#xff0c;AI Assistant for Observability 现已面向所有 Elastic 用户开放。AI Assistant 为 Elastic Observabi…

uniapp—android原生插件开发(1环境准备)

本篇文章从实战角度出发&#xff0c;将UniApp集成新大陆PDA设备RFID的全过程分为四部曲&#xff0c;涵盖环境搭建、插件开发、AAR打包、项目引入和功能调试。通过这份教程&#xff0c;轻松应对安卓原生插件开发与打包需求&#xff01; 项目背景&#xff1a; UniApp集成新大陆P…

git新手使用教程

git新手使用教程 一、安装和初始化配置2、新建仓库3.工作区域和文件状态4.添加和提交文件5 git reset回退版本6 使用git diff查看差异7 使用git rm删除文件8 .gitignore忽略文件9 注册GitHub账号10 SSH配置和克隆仓库11 关联本地仓库和远程仓库12 Gitee的使用 由B站视频教程整理…

java程序优化二

接触渲染也有一段时间了&#xff0c;发现还有很多优化的空间&#xff0c;今天时间比较有限就提一点 一&#xff1a;从参数接口方面&#xff0c;例如提交渲染接口参数有大量的浮点数据&#xff0c;小数位过多&#xff0c;其实四舍五入保留4位也没什么影响&#xff0c;这样大小接…

分布式----Ceph部署(上)

目录 一、存储基础 1.1 单机存储设备 1.2 单机存储的问题 1.3 商业存储解决方案 1.4 分布式存储&#xff08;软件定义的存储 SDS&#xff09; 1.5 分布式存储的类型 二、Ceph 简介 三、Ceph 优势 四、Ceph 架构 五、Ceph 核心组件 #Pool中数据保存方式支持两种类型&…

在SpringBoot3中启用HTTP2

为什么要在SpringBoot中启用HTTP2 启用HTTP2可以带来更高效的数据传输、更优的性能表现以及更好的用户体验。 二进制格式传输数据&#xff1a;HTTP2采用二进制格式传输数据&#xff0c;而非HTTP1.x的文本格式&#xff0c;这使得协议解析更高效&#xff0c;且便于扩展。 头部压…

HCIP(核心技术篇)—RSTP实验配置

一、回顾STP和STP的缺点和不足 1.STP的概述&#xff1a; STP&#xff08;生成树协议&#xff09;是一种用于在网络中防止产生环路的链路管理协议。 2.STP的作用&#xff1a; 解决二层环路&#xff0c;防止广播报文产生。但是网络拓扑收敛较慢&#xff0c;影响通信质量。 3…

【数据库实验一】数据库及数据库中表的建立实验

目录 实验1 学习RDBMS的使用和创建数据库 一、 实验目的 二、实验内容 三、实验环境 四、实验前准备 五、实验步骤 六、实验结果 七、评价分析及心得体会 实验2 定义表和数据库完整性 一、 实验目的 二、实验内容 三、实验环境 四、实验前准备 五、实验步骤 六…

在线绘制cancer cell同款双向条形图展示富集结果

导读&#xff1a;将上调和下调pathway富集结果以双向条形图的形式在一张图中展示&#xff0c;不仅优化了绘图空间&#xff0c;还通过对称布局增强了图片的美观性。 《Cancer cell》文章“Cross-tissue human fibroblast atlas reveals myofibroblast subtypes with distinct ro…

Linux(文件特殊属性 + FACL 图片+大白话)

后面也会持续更新&#xff0c;学到新东西会在其中补充。 建议按顺序食用&#xff0c;欢迎批评或者交流&#xff01; 缺什么东西欢迎评论&#xff01;我都会及时修改的&#xff01; 在这里真的很感谢这位老师的教学视频让迷茫的我找到了很好的学习视频 王晓春老师的个人空间…

json转excel,读取json文件写入到excel中【rust语言】

一、rust代码 将json文件写入到 excel中。&#xff08;保持json &#xff1a;key原始顺序&#xff09; use indexmap::IndexMap; use serde::Deserialize; use serde_json::{Value, from_str}; use std::error::Error; use std::io::{self, Write}; use std::path::{Path}; u…

理想火车站定位(字节青训)

题目 小F是A市的市长&#xff0c;正在计划在A市新建一个火车站以方便市民的日常出行。市区内的街道布局十分规整&#xff0c;形成网格状。从一个位置[x1, y1]到另一个位置[x2, y2]的距离计算方法为 |x1 - x2| |y1 - y2|&#xff0c;即曼哈顿距离。 在初步考察后&#xff0c;…

5位机械工程师如何共享一台工作站的算力?

在现代化的工程领域中&#xff0c;算力已成为推动创新与技术进步的关键因素之一。对于机械工程师而言&#xff0c;强大的计算资源意味着能够更快地进行复杂设计、模拟分析以及优化工作&#xff0c;从而明显提升工作效率与项目质量。然而&#xff0c;资源总是有限的&#xff0c;…

使用微信云开发,实现链接激活微信小程序(微信内部和外部H5访问)

首先小程序项目开发&#xff0c;需得支持云开发如何开通云开发&#xff1f;&#xff08;网上教程很多&#xff0c;也很全面&#xff0c;这里仅带过&#xff09; 配置云函数在项目根目录找到 project.config.json 文件&#xff0c;新增 cloudfunctionRoot 字段&#xff0c;指定本…

NVM 介绍及使用指南

在日常的开发工作中&#xff0c;我们往往会遇到需要在同一台机器上同时管理多个版本的 Node.js 的情况。为了解决这个问题&#xff0c;我一个同事推荐了NVM&#xff08;Node Version Manager&#xff09;。NVM 是一个用于管理 Node.js 版本的工具&#xff0c;可以方便地在不同的…

vscode 全局搜索的用法:

搜索栏最右边功能是区分大小写&#xff0c;全字匹配&#xff08;比如搜索abc&#xff0c;就不会显示abcd或者ab这些内容&#xff09;&#xff0c;使用正则表达式。变成高亮就是开启对应功能。包含的文件&#xff1a;这栏里如果最右边高亮填入带路径的文件&#xff0c;指的是在文…

如何从 Nutanix 迁移至 SmartX 超融合?解读 4 类迁移方案和 2 例迁移实践

随着 Nutanix&#xff08;路坦力&#xff09;将大陆区域的销售和部分维保工作交由联想负责&#xff0c;不少用户也在寻求 Nutanix 的替代方案。现阶段是否有必要换掉 Nutanix&#xff1f;有哪些成熟的国产替代方案&#xff1f;这些方案在性能和功能上是否具备与 Nutanix 同等的…

C++常见概念问题(3)

C常见概念问题&#xff08;3&#xff09; 1. 构造函数的初始化顺序 基类构造函数&#xff1a;在派生类的构造函数中&#xff0c;基类的构造函数在派生类构造函数体执行之前调用。 成员变量初始化&#xff1a;类中的成员变量会按照其在类中声明的顺序进行初始化&#xff0c;而…

「QT」几何数据类 之 QVector2D 二维向量类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…