SpringBoot集成与应用Neo4j

news2024/11/26 19:53:55

文章目录

  • 前言
  • 集成
  • 使用
    • 定义实体
    • 配置
    • 定义Repository
    • 查询方法
      • 方式一:@Query
      • 方式二:Cypher语法构建器
      • 方式三:Example条件构建器
      • 方式四:DSL语法
    • 自定义方法
      • 自定义接口
      • 继承自定义接口
      • 实现自定义接口
        • neo4jTemplate
        • Neo4jClient
      • 自定义抽象类(执行与结果转换)

前言

本篇主要是对neo4j的集成应用,会给出普遍的用法,但不是很详细,如果需要详细的话,每种方式都可以单独一篇说明,但应用都是举一反三,并没有必要都进行详解,而且,一些特殊的用法也举例了,也给出了一个自定义方式的查询和结果转换,虽然算不上完美,但也是很简单的,也希望大家有所收获。

集成

使用高版本的Spring data,我boot版本2.7,下面两个依赖,随便引入一个就行,我试过都是可以地

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-neo4j</artifactId>
        </dependency>
<!--两者任选其一,-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-neo4j</artifactId>
            <version>3.3.11</version>
        </dependency>

使用

定义实体

我们先定义三个实体

  • job:作业实体
  • table:表实体
  • JobRelationship:关系实体
@Data
@Node("Job")
public class Job {

    @Id
    @GeneratedValue
    private Long id;

    private String name;
    @Property
    private String type;

    @Relationship("dep")
    private List<TableRelationship> tables;

    @Relationship("dep")
    private List<JobRelationship> jobs;
}

@Data
@Node
public class Table {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    private String type;

    @Relationship("dep")
    private List<Job> jobs;
}

@Data
@RelationshipProperties
public class JobRelationship {
    @Id
    @GeneratedValue
    private Long id;

    @TargetNode
    private Job job;
}

@Data
@RelationshipProperties
public class TableRelationship {
    @Id
    @GeneratedValue
    private Long id;

    @TargetNode
    private Table table;
}

上面三个实体的写法都一些不同,这里需要注意下:

  1. @Node:标注的实体为数据库对象实体,表示一个节点,其value值就是标签,如果不设置就是类名;
  2. @Id:标注的属性是主键字段;
  3. @GeneratedValue:主键字段,必须设置它的一个生成方式,如果是自己设置可以忽略;
  4. @Property标注的属性为数据库属性字段,可以不写这个注解,@Node标注的实体中的属性默认为数据库属性字段,同样,其value值也是数据库属性字段,也可以不写,类似做了映射;
  5. @Relationship:标注的属性为关系属性,值为关系的标签值,另一个值为关系的指向,默认从当前节点向外指向,类似关系型数据库的关系;
  6. @RelationshipProperties:标注的类为关系实体,是对@Relationship类型的描述;
  7. @TargetNode:标注的属性是关系中的目标节点;

更加详细说明在:spring Data Neo4j

配置

application.yml

spring:
  neo4j:
    uri: bolt://192.168.0.103:7687
    authentication:
      username: neo4j
      password: password

定义Repository

这里使用的是spring jpa的开发方式,它提供了增删改查的基础功能,定义如下:

@Repository
public interface TableRepository extends Neo4jRepository<Table, Long> {
}
@Repository
public interface JobRepository extends Neo4jRepository<Job, Long> {
    /**
     * 根据名称查找
     */
    Job findByName(String name);

    /**
     * 节点name是否包含指定的值
     */
    boolean existsByNameContaining(String name);

    /**
     * 强制删除节点
     */
    Long deleteByName(String name);
}

那这个JPA的方式的话可以通过关键字和属性名定义查询方法,如上面的的findByName就可以实现通过名称查询,不需要写实现,这里只说这么多,详细的可以看:Spring Data JPA - Reference Documentation

查询方法

spring data提供的基础增删改查其实在在业务中是不够用的,但是,它额外的提供了一些条件构建器,使得我们可以借助一些快捷的API进行查询条件构造,以适应这些复杂查询,也就是动态语法。

方式一:@Query

说起JPA,自定义查询好像大多是用@Query注解进行标注的,比如:

    @Query("match(a:Job{name:$name}) return a")
    Job findByName2(@Param("name") String name);

    @Query("match(a:Job{name: $0) return a")
    List<Job> findByName3(@Param("name") String name);

这样的方式很简单是不是,但是存在的问题是,语句中的Job,name都是对应数据库里的标签和字段,所以这就和mybatis xml里的方式一样,如果数据库字段变更或标签变更需要全局替换。

方式二:Cypher语法构建器

Spring data提供了针对Cypher语法的构建器,可以让我们对复杂cypher的语法构建;

示例一:

match(a:Job) where a.name=‘liry’ return a order by a.id limit 1

// match(a:Job) where a.name='liry' return a order by a.id  limit 1

// 创建节点对象:标签为 Job,别名 a  -> (a:Job)
Node temp = Cypher.node("Job").named("a");
// 构建查询声明对象
// 创建match查询:-> match(a:Job)
ResultStatement statement = Cypher.match(temp)
                                    // 添加条件:-> a.name=$name
                                    .where(temp.property("name").isEqualTo(Cypher.anonParameter(job.getName())))
                                    // 返回对象:return 别名 -> return a
                                    .returning(temp.getRequiredSymbolicName())
                                    // 排序:以属性id正序
                                    .orderBy(temp.property("id"))
                                    // 限制数量:1
                                    .limit(1)
                                    // 构建为语法对象
                                    .build();

示例二:

//  merge(a:Job{name:$name}) set a.type=$type return a

// 构建参数
Map<String, Object> pro = new HashMap<>();
pro.put("name", job.getName());
// 创建节点对象:标签Job,别名a,并且设置参数  -> (a:Job{name:$name})
Node temp = Cypher.node("Job").named("a").withProperties(pro);
// 创建merge查询: -> merge(a:Job{name:$name})
ResultStatement statement = Cypher.merge(temp)
                                    // 设置值:-> a.type=$type
                                    .set(temp.property("type"),Cypher.anonParameter(job.getType()))
                                    // 返回对象:return别名 -> return a
                                    .returning(temp.getRequiredSymbolicName())
                                    // 构建声明对象
                                    .build();

示例三:

// MATCH (a:`Job` {name: $pcdsl01})-[r*..2]-(b:`Job`) RETURN a,b,r

// 创建两个节点给,都死标签Job,别名分别是a,b,a节点关联属性name
Node node = Cypher.node("Job").named("a").withProperties("name", Cypher.anonParameter(name));
Node node2 = Cypher.node("Job").named("b");

// 创建a-r-b的关系
Relationship r = node.relationshipBetween(node2).named("r").max(length);
// a-r->b
//        Relationship r = node.relationshipTo(node2).named("r").max(length);
// a<-r-b
//        Relationship r = node.relationshipFrom(node2).named("r").max(length);
// 创建match查询
ResultStatement statement = Cypher.match(r)
                                    // 返回对象
                                    .returning("a","b","r")
                                    // 构建声明对象
                                    .build();

这里的withProperties,我又用了另一种方式.withProperties("name", Cypher.anonParameter(name));,上面我传的是一个map,它这里其实很巧妙的做了一个适配,只要你以key value,那么便是偶数个参数,他会自动帮你绑定,或者传map也行。

方式三:Example条件构建器

Spring Data默认的Neo4jRepository是继承 了QueryByExampleExecutor,如下:

image-20231028185641361

那么它所能使用的方法是这些:

image-20231028222339087

其应用示例一:

// Neo4jRepository默认继承了example功能
        Job job = new Job();
        job.setName("liry");
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                                                      .withMatcher("na", ExampleMatcher.GenericPropertyMatchers.endsWith());
        // 根据示例匹配器规则进行条件重组 查询
        List<Job> all1 = jobRepository.findAll(Example.of(job, exampleMatcher));
        // 精确查询
        List<Job> all2 = jobRepository.findAll(Example.of(job));

        List<Job> all3 = jobRepository.findAll(Example.of(job), Sort.by(Sort.Order.desc("id")));
        
        Page<Job> all4 = jobRepository.findAll(Example.of(job), PageRequest.of(1, 10));

示例二:

流处理查询

  Job job = new Job();
        job.setJobName(name);
        // 查询一个一个值
        Job one = jobRepository.findBy(Example.of(job), query -> query.oneValue());
        // lambda简化
//        Job one = jobRepository.findBy(Example.of(job), FluentQuery.FetchableFluentQuery::oneValue);
        // 查询count
        Long count = jobRepository.findBy(Example.of(job), query -> query.count());
        // lambda简化
//        Long count = jobRepository.findBy(Example.of(job), FluentQuery.FetchableFluentQuery::count);
        // 是否存在
        Boolean exist = jobRepository.findBy(Example.of(job), query -> query.exists());
        // lambda简化
//        Boolean exist = jobRepository.findBy(Example.of(job), FluentQuery.FetchableFluentQuery::exists);
        // 查询全部
                List<Job> list = jobRepository.findBy(Example.of(job), query -> query.all());
        // lambda简化
//                List<Job> list = jobRepository.findBy(Example.of(job), FluentQuery.FetchableFluentQuery::all);
        // 查询2个
        List<Job> list2 = jobRepository.findBy(Example.of(job),
                                               query -> query.stream().limit(2).collect(Collectors.toList()));
        // 查询并进行处理
        List<Object> list3 = jobRepository.findBy(Example.of(job),
                                                  query -> query.stream().peek(d -> d.setName(d.getName() + "1")).collect(
                                                      Collectors.toList()));
        // 查询并排序
        List<Job> list4 = jobRepository.findBy(Example.of(job),
                                               query -> query.sortBy(Sort.by(Sort.Order.asc("id")))).all();

上面这个流处理查询都可以用lambda表达式来处理。

注意:使用example查询时,不要有关联关系,不然他会报错,即不要有@Relationship这个注解

方式四:DSL语法

这个是借助DSL框架实现的语法构建,添加DSL依赖

        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
        </dependency>

添加插件

 <plugin>
     <groupId>com.mysema.maven</groupId>
     <artifactId>apt-maven-plugin</artifactId>
     <version>1.1.3</version>
     <executions>
         <execution>
             <goals>
                 <goal>process</goal>
             </goals>
             <configuration>
                 <outputDirectory>target/generated-sources/java</outputDirectory>
                 <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
             </configuration>
         </execution>
     </executions>
</plugin>
  1. 实体类上需要加上@Entity

但是只引入neo4j的依赖,是不行的,还需要jpa的依赖,因为JPA依赖数据库,所以可以先引入,生成之后,再删除掉。

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

然后maven compile编译,一下,会在target/generated-sources/java目录下找到生成的Q类,把它复制到我们实体目录下

image-20231028192712827

  1. 继承接口QuerydslPredicateExecutor

    它的使用方式和Example一样。

    @Repository
    public interface JobRepository extends Neo4jRepository<Job, Long> ,  QuerydslPredicateExecutor<Job>{
    }
    

    这个接口下的功能都可以使用

    image-20231028222117957

示例一:

 QJob job = QJob.job;
// name=$name
        Iterable<Job> all = jobRepository.findAll(job.name.eq(name));

// name like $name and type = $type
        BooleanExpression exp = job.name.like(name)
                                         .and(job.type.eq("test"));

        boolean exists = jobRepository.exists(exp);
        Iterable<Job> all1 = jobRepository.findAll(exp);
// 排序
        Iterable<Job> id = jobRepository.findAll(exp, Sort.by(Sort.Order.desc("id")));
// 分月
        Page<Job> all2 = jobRepository.findAll(exp, PageRequest.of(1, 10));
      // in查询  
        exp = job.name.in("liryc", "xx");
        jobRepository.findAll(exp);

示例二:

     // 查询一个一个值
        Job one = jobRepository.findBy(exp, query -> query.oneValue());
        // lambda简化
        //        Job one = jobRepository.findBy(exp, FluentQuery.FetchableFluentQuery::oneValue);
        // 查询count
        Long count = jobRepository.findBy(exp, query -> query.count());
        // lambda简化
        //        Long count = jobRepository.findBy(exp, FluentQuery.FetchableFluentQuery::count);
        // 是否存在
        Boolean exist = jobRepository.findBy(exp, query -> query.exists());
        // lambda简化
        //        Boolean exist = jobRepository.findBy(exp, FluentQuery.FetchableFluentQuery::exists);
        // 查询全部
        List<Job> list = jobRepository.findBy(exp, query -> query.all());
        // lambda简化
        //                List<Job> list = jobRepository.findBy(exp, FluentQuery.FetchableFluentQuery::all);
        // 查询2个
        List<Job> list2 = jobRepository.findBy(exp,
                                               query -> query.stream().limit(2).collect(Collectors.toList()));
        // 查询并进行处理
        List<Object> list3 = jobRepository.findBy(exp,
                                                  query -> query.stream().peek(d -> d.setName(d.getName() + "1")).collect(
                                                      Collectors.toList()));
        // 查询并排序
        List<Job> list4 = jobRepository.findBy(exp,
                                               query -> query.sortBy(Sort.by(Sort.Order.asc("id")))).all();

自定义方法

上面都是spring data自带的方法,已经可以实现大部分的复杂查询了,当时在业务层的时候我们一般不会把这些数据访问放在业务层中,这些都应该是置于底层作为最基本的数据能力,不该带入业务,并且也不该把数据访问的逻辑赤裸的放到业务层中,那么我们就会需要子党员方法。

自定义接口

public interface JobCustomRepository {

    /**
     * 查询所有
     */
    Object selectAll();

    /**
     * 保持节点信息,会先判断是否存在
     */
    Job saveCondition(Job job);

    /**
     * 创建或合并节点
     */
    Job saveMerge(Job job);
}

继承自定义接口

@Repository
public interface JobRepository extends Neo4jRepository<Job, Long> , JobCustomRepository {
    
}

实现自定义接口

@Component("jobCustomRepository")
public class JobCustomRepositoryImpl implements JobCustomRepository {
}

如此我们就可以在业务层中这样:

// 这里引入的接口,就具备了原本spring的能力,和你自定义的能力
@Autowired
    private JobRepository jobRepository;

neo4jTemplate

在自定义中可以引入这个作为执行类,这个类实现Neo4jOperations,template它是支持直接写cypher语句的,比如下面这个

image-20231029002709607

image-20231029003215340

如果需要参数分离的话,参数占位用$,那么cypher语句应该是这样:

match(a) where a.name=$name return a

示例:

        // 方式一:template执行cql字符串
        String cql = String.format("merge(a:Job{name:'%s'}) set a.time=2 return a", job.getName());
        List<Job> all = neo4jTemplate.findAll(cql, Job.class);

        // 方式二:cypher语句
        cql = String.format("merge(a:Job{name:'%s'}) set a.time=$time return a", job.getName());
        Map<String, Object> param = new HashMap<>();
        param.put("time", 1);
        all = neo4jTemplate.findAll(cql, param, Job.class);

        // 方式三:Cypher构建声明对象
        Map<String, Object> pro = new HashMap<>();
        pro.put("name", job.getName());
        Node temp = Cypher.node("Job").named("a").withProperties(pro);
        ResultStatement statement = Cypher.merge(temp)
                                          .set(temp.property("type"), Cypher.anonParameter(job.getType()))
                                          .returning(temp.getRequiredSymbolicName())
                                          .build();

        List<Job> all1 = neo4jTemplate.findAll(statement, statement.getParameters(), Job.class);
Neo4jClient

除了neo4jTemplate还可以用neo4jClient

示例

        String cpl = "match(a) where a.name contains 'liry' return a limit 1";

        // 执行cypher
        Result run = client.getQueryRunner().run(cpl);

        // 结果获取的方式
        // **** 注意,下面的几种方式中,只能选用一种,在结果读取后,就不能在读取了 ****
        // 方式一:迭代器
        while (run.hasNext()) {
            Record d = run.next();
            // 这几个的结构差不多
            List<Pair<String, Value>> fields = d.fields();
            List<Value> values = d.values();
            Map<String, Object> stringObjectMap = d.asMap();
            System.out.println(d);
        }

        // 方式二:lambda
        // 或者直接获取列表
        List<Record> list = run.list();
        List<Record> dd = list.stream().map(d -> {
            List<Pair<String, Value>> fields = d.fields();
            List<Value> values = d.values();
            Map<String, Object> stringObjectMap = d.asMap();

            return d;
        }).collect(Collectors.toList());

        // 方式三:函数式接口
        List<Object> result = run.list(map -> {
            return map;
        });

这里有需要注意的地方,就是在run执行后,只能获取一次结果,如上代码所示,不论用那种方式进行结果的获取,都只能获取一次;

自定义抽象类(执行与结果转换)

但是很多人就会觉得这个方式需要自己处理结果集,确实,它的这个结果集不是很友好,所以我这里也提供一个结果处理案例;

我这里就直接贴已经完成的代码了,可以直接复制使用,同时这个类也提供了执行cypher语句的方法,和JPA一样。

package com.liry.neo.repository;

import com.liry.neo.entity.RelationshipInfo;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.neo4j.driver.internal.types.InternalTypeSystem;
import org.neo4j.driver.internal.value.NodeValue;
import org.neo4j.driver.types.MapAccessor;
import org.neo4j.driver.types.Relationship;
import org.neo4j.driver.types.TypeSystem;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.neo4j.core.Neo4jOperations;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.data.neo4j.core.PreparedQuery;
import org.springframework.data.neo4j.core.mapping.EntityInstanceWithSource;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
 * @author ALI
 * @since 2023/10/25
 */
public abstract class AbstractCustomRepository implements ApplicationContextAware {
    protected ApplicationContext applicationContext;
    private Neo4jMappingContext neo4jMappingContext;
    private Neo4jTemplate neo4jTemplate;

    private static <T> Supplier<BiFunction<TypeSystem, MapAccessor, ?>> getAndDecorateMappingFunction(
        Neo4jMappingContext mappingContext, Class<T> domainType, @Nullable Class<?> resultType) {
        Assert.notNull(mappingContext.getPersistentEntity(domainType), "Cannot get or create persistent entity.");
        return () -> {
            BiFunction<TypeSystem, MapAccessor, ?> mappingFunction = mappingContext.getRequiredMappingFunctionFor(domainType);
            if (resultType != null && domainType != resultType && !resultType.isInterface()) {
                mappingFunction = EntityInstanceWithSource.decorateMappingFunction(mappingFunction);
            }
            return mappingFunction;
        };
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private Neo4jMappingContext getNeo4jMappingContext() {
        if (neo4jMappingContext == null) {
            neo4jMappingContext = applicationContext.getBean(Neo4jMappingContext.class);
        }
        return neo4jMappingContext;
    }

    private Neo4jTemplate getNeo4jTemplate() {
        if (neo4jTemplate == null) {
            neo4jTemplate = applicationContext.getBean(Neo4jTemplate.class);
        }
        return neo4jTemplate;
    }

    /**
     * 执行cypher查询
     *
     * @param domainType      实体类型
     * @param cypherStatement cypher语句
     * @param parameters      参数
     */
    protected <T> Neo4jOperations.ExecutableQuery<T> createExecutableQuery(Class<T> domainType, String cypherStatement,
                                                                           Map<String, Object> parameters) {
        return createExecutableQuery(domainType, domainType, cypherStatement, parameters);
    }

    /**
     * 执行cypher查询
     *
     * @param domainType      实体类型
     * @param resultType      返回的结果类型
     * @param cypherStatement cypher语句
     * @param parameters      参数
     */
    protected <T> Neo4jOperations.ExecutableQuery<T> createExecutableQuery(Class<?> domainType, Class<T> resultType, String cypherStatement,
                                                                           Map<String, Object> parameters) {
        PreparedQuery.OptionalBuildSteps<T> step = PreparedQuery.queryFor(resultType).withCypherQuery(cypherStatement).withParameters(parameters);
        // 基本类型转换
        if (!Number.class.isAssignableFrom(resultType) && !Boolean.class.isAssignableFrom(resultType) && !String.class.isAssignableFrom(resultType)) {
            Supplier<BiFunction<TypeSystem, MapAccessor, ?>> mappingFunction = getAndDecorateMappingFunction(getNeo4jMappingContext(),
                                                                                                             domainType,
                                                                                                             resultType);
            step.usingMappingFunction(mappingFunction);
        }
        return getNeo4jTemplate().toExecutableQuery(step.build());
    }

    protected <T> T mapping(Class<T> domainType, NodeValue node) {
        Object apply = getMappingFunction(domainType).get().apply(InternalTypeSystem.TYPE_SYSTEM, node);
        return (T) ((EntityInstanceWithSource) apply).getEntityInstance();
    }

    protected RelationshipInfo mapping(Relationship node) {
        RelationshipInfo result = new RelationshipInfo();
        result.setStart(node.startNodeId());
        result.setEnd(node.endNodeId());
        result.setType(node.type());
        result.setId(node.id());
        return result;
    }

    /**
     * 结果映射
     *
     * @param domainType 实体类型,也是结果类型
     * @return 映射方法
     */
    protected <T> Supplier<BiFunction<TypeSystem, MapAccessor, ?>> getMappingFunction(Class<T> domainType) {
        return () -> {
            BiFunction<TypeSystem, MapAccessor, T> mappingFunction = getNeo4jMappingContext().getRequiredMappingFunctionFor(domainType);
            return EntityInstanceWithSource.decorateMappingFunction(mappingFunction);
        };
    }
}

之后我们自定义的Repository就要继承这个抽象类,以达到可以直接使用的功能,如下:

@Component("jobCustomRepository")
public class JobCustomRepositoryImpl extends AbstractCustomRepository implements JobCustomRepository {
    @Autowired
    private Neo4jTemplate neo4jTemplate;
}

再定义一个关系实体:

@Data
public class RelationshipDto {
    
    private Long id;
    
    private Long start;
    
    private Long end;
    
    private String type;
}

然后我们查询并转换如下:

String cpl = "match(a:Job)-[r*]-(b:Job) return a,b,r";

// 执行cypher
Result run = client.getQueryRunner().run(cpl);


// 结果接受容器
Set<Object> nodes = new HashSet<>();
Set<Object> relationships = new HashSet<>();
// 结果转换
List<Record> list = run.list();
list.forEach(d -> {
    // cypher中,别名a,b是表示节点,那么这里就取 a,b的值转换为实体
    nodes.add(mapping(Job.class, (NodeValue) d.get("a")));
    nodes.add(mapping(Job.class, (NodeValue)d.get("b")));

    // 然后获取关系
    Value r = d.get("r");
    Value a = d.get("a");
    List<Object> reList = r.asList().stream().map(rd -> {
        System.out.println(rd);
        return mapping((org.neo4j.driver.types.Relationship) rd);
    }).collect(Collectors.toList());

    relationships.addAll(reList);
});

image-20231029121317200

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

服务器资源检查

1.检查CPU情况 # 型号及核数 cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c # 查看物理cpu个数 cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l # 查看逻辑cpu个数 cat /proc/cpuinfo | grep "processor" | wc -l cat /proc/…

python随手小练9(南农作业题)

题目1&#xff1a; 用python提供的相关函数计算数学表达式的值 具体操作&#xff1a; a float(input("x:")) #input()输入&#xff08;默认为字符串str形式&#xff09; #float()将()内类型转换为浮点型&#xff08;即有小数点&#xff09; b a (3*a)/4 #…

《你不知道的Javascript系列》——不可变性immutable

基础 JavaScript中存在以下数据类型&#xff1a; 原生&#xff08;基本&#xff09;类型 —— Boolean, Number, String非原始&#xff08;引用&#xff09;类型或对象 —— Object, Array, Function特殊 —— Null, Undefined 原生数据类型默认是不可变的&#xff0c;对于常…

好消息FL Studio21.2中文版本发布了!新功能详细介绍

为庆祝 FL Studio 21.2 的发布&#xff0c;所有 FL Studio 用户都可免费使用一个月的 FL Cloud。只需打开 FL Studio 21.2&#xff0c;点击浏览器中的 "声音 "标签即可开始使用。FL Cloud 提供完全集成的采样库、人工智能母带处理和由 DistroKid 支持的数字发行&…

bbr 流相互作用图示

类似 AIMD 收敛图&#xff0c;给出 bbr 的对应图示&#xff1a; bbr 多流相互作用非常复杂&#xff0c;和右下角的 AIMD 相比&#xff0c;毫无美感&#xff0c;但是看一眼左下角的 bbr 单流情况&#xff0c;又过于简陋&#xff0c;而 bbr 的核心就基于这简陋的假设。 浙江温…

【rust/esp32】在idf中使用embedded-graphics控制st7789 LCD屏幕

文章目录 说在前面模块详情准备工作开始编译烧录结果 说在前面 esp32版本&#xff1a;s3运行环境&#xff1a;esp-idf(std)开发环境&#xff1a;wsl2LCD模块&#xff1a;ST7789V2 240*280 LCDgithub地址&#xff1a;这里 模块详情 某宙的esp32s3开发板 某雪的1.69inch LCD模块…

78 子集

子集 题解1 回溯模板 题解2 迭代&#xff08;mask思想&#xff09; 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入…

AcWing 第127场周赛 构造矩阵

构造题目&#xff0c;考虑去除掉最后一行最后一列先进行考虑&#xff0c;假设除了最后一行和最后一列都已经排好了&#xff08;你可以随便排&#xff09;&#xff0c;那么分析知最后一个数字由限制以外其他都已经确定了&#xff0c;无解的情况是k为-1 并且n&#xff0c;m的奇偶…

网络编程套接字(1)——简单的UDP网络程序

文章目录 一.预备知识1.理解源IP地址和目的IP地址2.理解源MAC地址和目的MAC地址3.理解源端口号和目的端口号4.PORT VS PID5.认识TCP协议和UDP协议6.网络字节序 二.socket编程接口1.socket常见API2.sockaddr结构 三.简单的UDP网络程序1.服务端创建套接字2.服务端绑定3.字符串IP …

ctf md5爆破

1.知道组成的字符为数字,然后知道加密后的MD5,求组成的字符 import hashlibimport stringdef crackMd5(dst):dst dst.lower()for a in range(0,10):for b in range(0,10):for c in range(0,10):for d in range(0,10):word str(a) str(b) str(c) str(d) "_heetian&q…

【报错】kali安装ngrok报错解决办法(zsh: exec format error: ./ngrok)

问题描述 kali安装ngrok令牌授权失败 在安装配置文件的时候报错&#xff1a;zsh: exec format error: ./ngrok 原因分析&#xff1a; 在Kali Linux上执行./ngrok时出现zsh exec格式错误的问题可能是由于未安装正确版本的ngrok或操作系统不兼容ngrok导致的。以下是一些可能的解…

k8s安装时初始化报错:error execution phase preflight

服务器配置与k8s版本 系统版本&#xff1a; CentOS Linux release 7.9.2009 (Core)内核版本&#xff1a; [rootk8s-node02 tmp]# uname -r 5.4.259-1.el7.elrepo.x86_64k8s版本 v1.15.1 [rootk8s-node1 tmp]# kubeadm version kubeadm version: &version.Info{Major:&q…

(免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用Java技术建设农产品销售管理系统。…

人工智能(AI)在医疗领域的应用

人工智能&#xff08;AI&#xff09;在医疗领域的应用 人工智能&#xff08;AI&#xff09;在医疗领域的应用近年来得到了广泛的关注。其中&#xff0c;AI辅助治疗疾病的技术成为了研究热点。本文将介绍AI辅助治疗疾病的技术&#xff0c;包括其定义、应用场景、案例分析和发展…

jdk10的var局部变量类型推理

注&#xff1a;本人参考了openjdk官网&#xff0c;由于openjdk是开源的&#xff0c;所以不存在侵权行为&#xff0c;本章只为学习&#xff0c;我觉得没有什么比官网更具有话语权 1、jdk10的var的类型推测&#xff1a;就是这种处理将仅限于具有初始值设定项的局部变量、增强型 -…

Android问题笔记四十三:JNI 开发如何快速定位崩溃问题

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…

opencv 滤波与blob检测总结

参考&#xff1a;https://learnopencv.com/contour-detection-using-opencv-python-c/ import cv2 impory numpy as np image cv2.imread(rxxx.jpg) # Sobel Edge Detection sobelx cv2.Sobel(srcimg_blur, ddepthcv2.CV_64F, dx1, dy0, ksize21) # Sobel Edge Detection o…

Python程序设计期末复习笔记

文章目录 一、数据存储1.1 倒计时1.2 os库1.3 字符串操作1.4 文件操作1.5 列表操作1.6 元组1.7 字典 二、文本处理及可视化2.1 jieba分词2.2 集合操作2.3 pdf文件读取2.4 参数传递2.5 变量作用域 三、数据处理分析3.1 Sumpy3.2 Matplotlib3.3 Numpy 四、Pandas4.1 索引操作4.2 …

【算法|动态规划 | 01背包问题No.1】AcWing 426. 开心的金明

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【AcWing算法提高学习专栏】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&a…

Java Dubbo 微服务框架 HP-SOA

HP-SOA 功能完备&#xff0c;简单易用&#xff0c;高度可扩展的Java微服务框架。 【快速开始】 技术架构 技术集成 Web服务框架&#xff1a;spring-boot 3.x微服务框架&#xff1a;Dubbo 3.x服务注册中心&#xff1a;Nacos配置中心&#xff1a;Nacos服务治理中心&#xff1…