循序渐进 · 教学 · 函数(五)

函数类型参考手册

TypeScript 函数要发布到注册表,所有入参和返回值都必须显式标注类型。这一篇是全部可用类型的完整清单,写代码时当字典查。

全部目录 ← 上一篇 函数类型参考手册 下一篇 →
本文来源 · Source 内容整理自 Palantir Foundry 官方文档:
https://www.palantir.com/docs/foundry/functions/types-reference/
原始标题:Functions > Types reference

先记住这几条

① 类型必须显式标注
不写类型标注的函数无法发布,这是硬性要求。
② 七大类型族
标量 / 集合 / 聚合 / 本体 / 媒体 / 用户与组 / 几何,覆盖函数能处理的全部数据形态。
③ 本体类型是重点
Object、Object set、Interface、Ontology edit 是写业务函数最常用的几个。
④ Optional 要单独注意
可选类型在函数签名里的写法,直接影响参数的必填性。
0

写在前面

要将 TypeScript 函数发布到注册表,必须为所有输入参数添加显式类型注解,并指定显式返回类型。以下列出了当前支持的全部函数注册表类型及其对应的语言类型。

在 Pipeline Builder 中将 Python 函数用作用户自定义函数(UDF)?下面这些标量类型(如 strint)就是 UDF 返回的值,因为函数对每一行执行一次,其返回值会成为新的一列。你不需要返回 DataFrame。详细说明请查看Python 函数在 Pipeline Builder 中如何处理数据

Function registry typeTypeScript v1 typeTypeScript v2 typePython type
AttachmentAttachmentAttachmentAttachmentExample
BooleanbooleanbooleanboolExample
BinaryNot supportedNot supportedbytesExample
ByteNot supportedNot supportedint*Example
Classification markingClassificationMarkingClassificationMarkingClassificationMarkingExample
DateLocalDateDateISOStringdatetime.dateExample
DecimalNot supportedNot supporteddecimal.DecimalExample
DoubleDoubleDoublefloat*Example
FloatFloatFloatfloatExample
GeoPointGeoPointPointGeoPointExample
GeoShapeGeoShapeGeometryGeoShapeExample
GroupGroupGroupIdGroupIdExample
IntegerIntegerIntegerintExample
InterfaceNot supportedOsdk.Instance<MyInterface>Not supportedExample
Interface object setNot supportedObjectSet<MyInterface>Not supportedExample
ListT[] or Array<T>T[] or Array<T>list[T]Example
LongLongLongint*Example
Mandatory markingMandatoryMarkingMandatoryMarkingMandatoryMarkingExample
MapFunctionsMap<K, V>Record<K, V>dict[K, V]Example
Media referenceMediaItemMediaMediaExample
NotificationNotificationNotificationNotificationExample
ObjectMyObjectTypeOsdk.Instance<MyObjectType>MyObjectTypeExample
Object setObjectSet<MyObjectType>ObjectSet<MyObjectType>MyObjectTypeObjectSetExample
Ontology editvoidEditsOntologyEditExample
Optional`T \undefined``T \undefined`typing.Optional or `T \None`Example
PrincipalPrincipalPrincipalPrincipalExample
RangeIRange<T>Range<T>Range[T]Example
SetSet<T>Not supportedset[T]Example
ShortNot supportedNot supportedint*Example
StringstringstringstrExample
Struct/custom typeinterfaceinterfacedataclasses.dataclassExample
TimestampTimestampTimestampISOStringdatetime.datetimeExample
Two-dimensional aggregationTwoDimensionalAggregation<K, V>TwoDimensionalAggregation<K, V>TwoDimensionalAggregation[K, V]Example
Three-dimensional aggregationThreeDimensionalAggregation<K, S, V>ThreeDimensionalAggregation<K, S, V>ThreeDimensionalAggregation[K, S, V]Example
UserUserUserIdUserIdExample

尽管 IntegerLong 都对应 Python 的 int 类型,但函数签名中直接标注为 int 的字段会被注册为 Integer 类型。因此,我们建议改用 API 中的 IntegerLong 类型来注册数值型数据。FloatDouble 同理:如果函数签名中直接写了 Python 的 float 类型,默认会被注册为 Float

1

标量类型

标量类型

要点:Boolean / String / 各种数字 / Date / Timestamp / Binary 等基础类型,以及必填与安全分级标记。

标量类型表示单个值,通常用于保存文本、数值或时间数据。

在 JavaScript 和 TypeScript 中,只有一个 number 类型,通常既用来表示整数也表示浮点数。为了提供更强的类型校验与结构约束,我们仅支持从 @foundry/functions-api 包(TypeScript v1 函数)和 @osdk/functions 包(TypeScript v2 函数)导出的数值别名类型。类似地,在 Python 函数中使用数值类型时,我们建议使用 functions.api 模块导出的类型别名。

Boolean

import { Function, Integer } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public isEven(num: Integer): boolean {
        return num % 2 === 0;
    }
}
import { Integer } from "@osdk/functions";

function isEven(num: Integer): boolean {
    return num % 2 === 0;
}

export default isEven;
from functions.api import function, Integer

@function
def is_even(num: Integer) -> bool:
    return n % 2 == 0

String

import { Function } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public greet(name: string): string {
        return `Hello, ${name}!`;
    }
}
function greet(name: string): string {
    return `Hello, ${name}!`;
}

export default greet;
from functions.api import function

@function
def greet(name: str) -> str:
    return f"Hello, {name}!"

Short

表示 -32,768 到 32,767 之间的整数值。

在 Python 函数中,Short 类型是内置 int 类型的别名。

from functions.api import function, Short

@function
def increment(num: Short) -> Short:
    return num + 1

Integer

表示 (-2<sup>31</sup>) 到 (2<sup>31</sup> - 1) 之间的整数值。

  • 在 TypeScript v1 和 v2 函数中,Integer 类型都是内置 number 类型的别名。
  • 在 Python 函数中,Integer 类型是内置 int 类型的别名。
import { Function, Integer } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public sum(a: Integer, b: Integer): Integer {
        return a + b;
    }
}
import { Integer } from "@osdk/functions";

function sum(a: Integer, b: Integer): Integer {
    return a + b;
}

export default sum;
from functions.api import function, Integer

@function
def sum(a: Integer, b: Integer) -> Integer:
    return a + b

Long

表示 -(2<sup>53</sup> - 1) 到 (2<sup>53</sup> - 1) 之间的整数值。这些边界对应 JavaScript 中的 Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER,用于在函数从浏览器上下文调用时避免精度丢失。

  • 在 TypeScript v1 函数中,Long 类型是内置 number 类型的别名;在 TypeScript v2 函数中,Long 类型是内置 string 类型的别名。
  • 在 Python 函数中,Long 类型是内置 int 类型的别名。
import { Function, Long } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public subtract(a: Long, b: Long): string {
        return (BigInt(a) - BigInt(b)).toString();
    }
}
import { Long } from "@osdk/functions";

function subtract(a: Long, b: Long): string {
    return (BigInt(a) - BigInt(b)).toString();
}

export default subtract;
from functions.api import function, Long

@function
def subtract(a: Long, b: Long) -> str:
    return str(a - b)

Float

表示 32 位浮点数。

  • 在 TypeScript v1 和 v2 函数中,Float 类型都是内置 number 类型的别名。
  • 在 Python 函数中,Float 类型是内置 float 类型的别名。
import { Float, Function } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public multiply(a: Float, b: Float): Float {
        return a * b;
    }
}
import { Float } from "@osdk/functions";

function multiply(a: Float, b: Float): Float {
    return a * b;
}

export default multiply;
from functions.api import function, Float

@function
def multiply(a: Float, b: Float) -> Float:
    return a * b

Double

表示 64 位浮点数。

  • 在 TypeScript v1 和 v2 函数中,Double 类型都是内置 number 类型的别名。
  • 在 Python 函数中,Double 类型是内置 float 类型的别名。
import { Double, Function } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public divide(a: Double, b: Double): Double {
        return a / b;
    }
}
import { Double } from "@osdk/functions";

function divide(a: Double, b: Double): Double {
    return a / b;
}

export default divide;
from functions.api import function, Double

@function
def divide(a: Double, b: Double) -> Double:
    return a / b

Decimal

from decimal import Decimal
from functions.api import function

@function
def return_pi() -> Decimal:
    return Decimal('3.1415926535')

Date

表示日历日期。

import { Function, LocalDate } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public returnDate(): LocalDate {
        return LocalDate.fromISOString("1999-10-17");
    }
}
import { DateISOString } from "@osdk/functions";

function returnDate(): DateISOString {
    return "1999-10-17";
}

export default returnDate;
from datetime import date
from functions.api import function, Date

@function
def return_date() -> Date:
    return date.fromisoformat('1999-10-17')

Timestamp

表示时间轴上的一个时间点(时刻)。

import { Function, Timestamp } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public getCurrentTimestamp(): Timestamp {
        return Timestamp.now();
    }
}
import { TimestampISOString } from "@osdk/functions";

function getCurrentTimestamp(): TimestampISOString {
    const now = new Date();
    return now.toISOString();
}

export default getCurrentTimestamp;
from datetime import datetime
from functions.api import function, Timestamp

@function
def get_current_timestamp() -> Timestamp:
    return datetime.now()

Binary

在 Python 函数中,Binary 类型是内置 bytes 类型的别名。

from functions.api import function

@function
def encode_utf8(param: str) -> bytes:
    return param.encode('utf-8')

Byte

在 Python 函数中,Byte 类型是内置 int 类型的别名。

from functions.api import function, Byte

@function
def get_first_byte(param: str) -> Byte:
    if len(param) == 0:
        raise Exception("String length cannot be zero.")
    return param.encode('utf-8')[0]

Mandatory marking

标记(Marking)是一种强制访问控制,要求用户必须拥有特定标记才能访问相应数据。

import { OntologyEditFunction, MandatoryMarking } from "@foundry/functions-api";
import { Employee, Objects } from "@foundry/ontology-api";

export class MyFunctions {
    @Edits(Employee)
    @OntologyEditFunction()
    public async editMandatoryMarkings(markings: MandatoryMarking[]): Promise<void> {
        const employeeOne = Objects.search().employee().filter(e => e.id.exactMatch(1)).all()[0];
        employeeOne.markingsProperty = markings;
    }
}
import { Client } from "@osdk/client";
import { Employee } from "@ontology/sdk";
import { Edits, createEditBatch, MandatoryMarking } from "@osdk/functions";

type OntologyEdit = Edits.Object<Employee>;

function editMandatoryMarkings(markings: MandatoryMarking[]): OntologyEdit[] {
    const batch = createEditBatch<OntologyEdit>(client);

    const employeeOne = await client(Employee).fetchOne(1);
    batch.update(employeeOne, { markingsProperty: markings });

    return batch.getEdits();
}

export default editMandatoryMarkings;
from foundry_sdk_runtime import Marking
from functions.api import function, MandatoryMarking, OntologyEdit
from ontology_sdk import FoundryClient
from ontology_sdk.ontology.objects import Employee

@function
def edit_mandatory_markings(markings: list[MandatoryMarking]) -> list[OntologyEdit]:
    ontology_edits = FoundryClient().ontology.edits()
    employee: Optional[Employee] = client.ontology.objects.Employee.get("primary_key")
    if employee is None:
        return []
    editable_employee = ontology_edits.objects.Employee.edit(employee)

    editable_employee.markings_property = [Marking(m) for m in markings]
    # Assigning type "list[MandatoryMarking]" also works, but gives an LSP warning:
    # editable_employee.markings_property = markings

    return ontology_edits.get_edits()

Classification marking

基于分类的访问控制(CBAC)是一种强制访问控制,用于保护敏感的政府信息。它要求用户必须拥有特定分类标记才能访问相应信息。

import { OntologyEditFunction, ClassificationMarking } from "@foundry/functions-api";
import { Employee, Objects } from "@foundry/ontology-api";

export class MyFunctions {
    @Edits(Employee)
    @OntologyEditFunction()
    public async editClassificationMarkings(markings: ClassificationMarking[]): Promise<void> {
        const employeeOne = Objects.search().employee().filter(e => e.id.exactMatch(1)).all()[0];
        employeeOne.markingsProperty = markings;
    }
}
import { Client } from "@osdk/client";
import { Employee } from "@ontology/sdk";
import { Edits, createEditBatch, ClassificationMarking } from "@osdk/functions";

type OntologyEdit = Edits.Object<Employee>;

function editClassificationMarkings(markings: ClassificationMarking[]): OntologyEdit[] {
    const batch = createEditBatch<OntologyEdit>(client);

    const employeeOne = await client(Employee).fetchOne(1);
    batch.update(employeeOne, { markingsProperty: markings });

    return batch.getEdits();
}

export default editClassificationMarkings;
from foundry_sdk_runtime import Marking
from functions.api import ClassificationMarking, function, OntologyEdit
from ontology_sdk import FoundryClient
from ontology_sdk.ontology.objects import Employee

@function
def edit_classification_markings(markings: list[ClassificationMarking]) -> list[OntologyEdit]:
    ontology_edits = FoundryClient().ontology.edits()
    employee: Optional[Employee] = client.ontology.objects.Employee.get("primary_key")
    if employee is None:
        return []
    editable_employee = ontology_edits.objects.Employee.edit(employee)

    editable_employee.markings_property = [Marking(m) for m in markings]
    # Assigning type "list[ClassificationMarking]" also works, but gives an LSP warning:
    # editable_employee.markings_property = markings

    return ontology_edits.get_edits()
2

集合类型

集合类型

要点:List / Map / Set / Optional / 自定义结构体,用来描述复合数据。

集合类型由其他类型参数化。例如,Array[String] 是字符串列表,Map[String, Integer] 是以字符串为键、整数为值的字典。必须显式指定参数化类型,且该类型必须是另一种受支持的类型。Map 的键只能是标量类型或 Ontology 对象类型。

List

import { Function, Integer } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public filterForEvenIntegers(nums: Integer[]): Integer[] {
        return nums.filter(num => num % 2 === 0);
    }
}
import { Integer } from "@osdk/functions";

function filterForEvenIntegers(nums: Integer[]): Integer[] {
    return nums.filter(num => num % 2 === 0);
}

export default filterForEvenIntegers;
from functions.api import function, Integer

@function
def filter_for_even_integers(nums: list[Integer]) -> list[Integer]:
    return [n for n in nums if n % 2 == 0]

Map

Map 通常用于以标量类型为键,访问与之关联、且可为任何其他函数注册表类型的值。

import { Function, FunctionsMap } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public getMap(): FunctionsMap<string, string> {
        const myMap = new FunctionsMap<string, string>();

        myMap.set("Name", "Phil");
        myMap.set("Favorite Color", "Blue");

        return myMap;
    }
}
function getMap(): Record<string, string> {
    const myMap: Record<string, string> = {};

    myMap["Name"] = "Phil";
    myMap["Favorite Color"] = "Blue";

    return myMap;
}

export default getMap;
from functions.api import function

@function
def get_map() -> dict[str, str]:
    my_map = {}

    my_map["Name"] = "Phil"
    my_map["Favorite Color"] = "Blue"

    return my_map

此外,Map 还支持以 Ontology 对象作为键。

import { Function, FunctionsMap } from "@foundry/functions-api";
import { Airplane } from "@foundry/ontology-api";

export class MyFunctions {
    @Function()
    public getObjectMap(aircraft: Airplane[]): FunctionsMap<Airplane, Integer | undefined> {
        const myMap = new FunctionsMap<Airplane, Integer | undefined>();

        aircraft.forEach(obj => {
            myMap.set(obj, obj.capacity);
        });

        return myMap;
    }
}
import { ObjectSpecifier, Osdk } from "@osdk/client";
import { Integer } from "@osdk/functions";
import { Airplane } from "@ontology/sdk";

function getObjectMap(aircraft: Osdk.Instance<Airplane>[]): Record<ObjectSpecifier<Airplane>, Integer | undefined> {
    const myMap: Record<ObjectSpecifier<Airplane>, Integer | undefined> = {};

    aircraft.forEach(obj => {
        myMap[obj.$objectSpecifier] = obj.capacity;
    });

    return myMap;
}

export default getObjectMap;
from functions.api import function, Integer
from ontology_sdk.ontology.objects import Airplane

@function
def get_object_map(aircraft: list[Airplane]) -> dict[Airplane, Integer | None]:
    my_map = {}

    for a in aircraft:
        my_map[a] = a.capacity

    return my_map

Set

import { Function, Integer } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public getSizeOfSet(mySet: Set<Integer>): Integer {
        return mySet.size;
    }
}
from functions.api import function, Integer

@function
def get_size_of_set(my_set: set[Integer]) -> Integer:
    return len(my_set)

Optional

  • 在 TypeScript 函数中,可选参数声明为 varName?: TvarName: T | undefined。例如,一个带有名为 value 的可选整数参数的函数,可声明为 value?: Integervalue: Integer | undefined。TypeScript 函数也可以通过指定 T | undefined 类型来声明可选返回类型。例如,一个可能返回 Integer 或不返回任何值的函数,其返回类型为 Integer | undefined
  • 在 Python 函数中,可选参数和返回值可使用 typing.Optional[T]T | None 声明。T | None 语法需要 Python 3.10 或以上版本。
  • 在 TypeScript 和 Python 函数中,都必须显式指定参数化类型 T,且它必须是另一种受支持的类型。
import { Function } from "@foundry/functions-api";

export class MyFunction {
    @Function()
    public greet(name?: string): string | undefined {
        if (name === undefined) {
            return undefined;
        }
        return `Hello, ${name}!`;
    }
}
function greet(name?: string): string | undefined {
    if (name === undefined) {
        return undefined;
    }
    return `Hello, ${name}!`;
}

export default greet;
from functions.api import function

@function
def greet(name: str | None) -> str | None:
    if name is None:
        return None
    return f"Hello, {name}!"

函数还支持在函数签名中使用默认值。

import { Double, Function } from "@foundry/functions-api";
import { Customer } from "@foundry/ontology-api";

export class MyFunctions {
    @Function()
    public computeRiskFactor(customer: Customer, weight: Double = 0.75): Double {
        // ...
    }
}
import { Double } from "@osdk/functions";
import { Osdk } from "@osdk/client";
import { Customer } from "@ontology/sdk";

function computeRiskFactor(customer: Osdk.Instance<Customer>, weight: Double = 0.75): Double {
    // ...
}

export default computeRiskFactor;
from functions.api import function, Double
from ontology_sdk.ontology.objects import Customer

@function
def compute_risk_factor(customer: Customer, weight: Double = 0.75) -> Double:
    # ...

Struct/custom type

自定义类型由其他受支持的类型(包括其他自定义类型)组合而成,可用于函数签名。

函数签名中使用的自定义类型,与用于 Ontology 结构体属性的生成类不同。若要在 Python 函数中编辑 Ontology 结构体属性,请使用生成的 struct 属性类,详见编辑结构体属性

  • 在 TypeScript 函数中,自定义类型是使用 interface 关键字定义的 TypeScript 接口。
  • 可选字段可通过 ? 可选标记,或与 undefined 组成的联合类型来支持。
  • 在 Python 函数中,自定义类型是用户自定义的 Python 类。
  • 要成为有效的自定义类型,该类必须满足以下要求:
  • 类的所有字段都必须有类型注解。
  • 字段类型必须是受支持的类型;可使用基础 API 类型或原生 Python 类型(如上文表格中所定义)。
  • __init__ 方法只能接受命名参数,且参数名与类型注解必须与字段一致。
  • 可使用 dataclasses.dataclass ↗ 装饰器自动生成符合上述要求的 __init__ 方法。
import { Function, Integer } from "@foundry/functions-api";
import { Passenger } from "@foundry/ontology-api";

interface PassengerInfo {
    name?: string;
    age?: Integer;
}

export class MyFunctions {
    @Function()
    public getPassengerInfo(passenger: Passenger): PassengerInfo {
        return {
            name: passenger.name,
            age: passenger.age,
        };
    }
}
import { Osdk } from "@osdk/client";
import { Integer } from "@osdk/functions";
import { Passenger } from "@ontology/sdk";

interface PassengerInfo {
    name?: string;
    age?: Integer;
}

function getPassengerInfo(passenger: Osdk.Instance<Passenger>): PassengerInfo {
    return {
        name: passenger.name,
        age: passenger.age,
    };
}

export default getPassengerInfo;
from dataclasses import dataclass
from functions.api import function, Integer
from ontology_sdk.ontology.objects import Passenger

@dataclass
class PassengerInfo:
    name: str | None
    age: Integer | None

@function
def get_passenger_info(passenger) -> PassengerInfo:
    return PassengerInfo(
        name=passenger.name,
        age=passenger.age
    )
3

聚合类型

聚合类型

要点:Range 与二维、三维聚合,用于统计结果的表示。

聚合类型可从函数返回,供平台的其它部分使用,例如 Workshop 中的图表。

支持两种聚合类型:

  • 二维聚合 将单个分桶键映射到一个数值。例如,可用于表示「具有特定职位的员工数量」这样的聚合。
  • 三维聚合 将两个分桶键映射到一个数值。例如,可用于表示「按员工职位和所属办公室统计的员工数量」这样的聚合。

聚合可以按以下几种类型作为键:

  • Boolean 分桶表示值为 truefalse
  • String 分桶可用于表示分类值。
  • Range 分桶表示以值区间作为分桶键的聚合。可用于在图表中表示直方图或日期轴。
  • 数值区间(包括 IntegerDouble)表示对数值的分桶聚合。
  • 日期与时间区间(包括 DateTimestamp)表示对日期区间的分桶聚合。

Range

各版本字段名不同。TSv1 的 IRange<T> 和 Python 的 Range[T] 使用 minmax;TSv2 的 Range<T> 使用 startValueendValue,且可省略其中之一以表示开区间。

import { Function, Integer, IRange } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public getRange(min: Integer, max: Integer): IRange<Integer> {
        return {
            min,
            max,
        };
    }
}
import { Integer, Range } from "@osdk/functions";

function getRange(min: Integer, max: Integer): Range<Integer> {
    return {
        startValue: min,
        endValue: max,
    };
}

export default getRange;
from functions.api import function, Integer, Range

@function
def get_range(min: Integer, max: Integer) -> Range[Integer]:
    return Range(
        min=min,
        max=max
    )

Two-dimensional aggregation

import { Double, Function, TwoDimensionalAggregation } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public myTwoDimensionalAggregation(): TwoDimensionalAggregation<string, Double> {
        return {
            buckets: [
                { key: "bucket1", value: 5.0 },
                { key: "bucket2", value: 6.0 },
            ],
        };
    }
}
import { Double, TwoDimensionalAggregation } from "@osdk/functions";

function myTwoDimensionalAggregationFunction(): TwoDimensionalAggregation<string, Double> {
    return [
        { key: "bucket1", value: 5.0 },
        { key: "bucket2", value: 6.0 },
    ];
}

export default myTwoDimensionalAggregationFunction;
from functions.api import (
    function,
    Double,
    TwoDimensionalAggregation,
    SingleBucket
)

@function
def my_two_dimensional_aggregation_function() -> TwoDimensionalAggregation[str, Double]:
    return TwoDimensionalAggregation(
        buckets=[
            SingleBucket(key="bucket1", value=Double(5.0)),
            SingleBucket(key="bucket2", value=Double(6.0)),
        ]
    )

Three-dimensional aggregation

分桶结构在各版本间不同。TSv1 将外层分桶包裹在 buckets 键下,内层以 value 为键。TSv2 返回一个扁平数组,内层位于 groups 下,因此 ThreeDimensionalAggregation<T, U, V> 解析为 { key: T; groups: { key: U; value: V }[] }[]。Python 与 TSv1 一样包裹外层分桶,并通过 NestedBucketSingleBucket 类构建。

import { Double, Function, ThreeDimensionalAggregation } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public myThreeDimensionalAggregation(): ThreeDimensionalAggregation<string, string, Double> {
        return {
            buckets: [
                {
                    key: "group-by-1",
                    value: [
                        { key: "partition-by-1", value: 5.0 },
                        { key: "partition-by-2", value: 6.0 },
                    ],
                },
                {
                    key: "group-by-2",
                    value: [
                        { key: "partition-by-1", value: 7.0 },
                        { key: "partition-by-2", value: 8.0 },
                    ],
                },
            ]
        };
    }
}
import { Double, ThreeDimensionalAggregation } from "@osdk/functions";

function myThreeDimensionalAggregation(): ThreeDimensionalAggregation<string, string, Double> {
    return [
        {
            key: "group-by-1",
            groups: [
                { key: "partition-by-1", value: 5.0 },
                { key: "partition-by-2", value: 6.0 },
            ],
        },
        {
            key: "group-by-2",
            groups: [
                { key: "partition-by-1", value: 7.0 },
                { key: "partition-by-2", value: 8.0 },
            ],
        },
    ];
}

export default myThreeDimensionalAggregation;
from functions.api import (
    function,
    Double,
    ThreeDimensionalAggregation,
    SingleBucket,
    NestedBucket,
)

@function
def my_three_dimensional_aggregation_function() -> (
    ThreeDimensionalAggregation[str, str, Double]
):
    return ThreeDimensionalAggregation(
        buckets=[
            NestedBucket(key="group-by-1", buckets=[
                SingleBucket(key="partition-by-1", value=Double(5.0)),
                SingleBucket(key="partition-by-2", value=Double(6.0)),
            ]),
            NestedBucket(key="group-by-2", buckets=[
                SingleBucket(key="partition-by-1", value=Double(7.0)),
                SingleBucket(key="partition-by-2", value=Double(8.0)),
            ])
        ]
    )
4

本体类型

本体类型

要点:Object、Object set、Interface、Ontology edit、Attachment、Notification —— 业务函数的核心。

要在函数签名中使用对象类型,必须先将它们导入到你的代码仓库。了解有关 Ontology 导入的更多信息。

Object

来自你的 Ontology 的对象类型,既可作为函数签名的输入,也可作为输出。若要接收或返回单个对象类型实例,请从 Ontology SDK 导入该对象类型,并用它来注解你的函数。

import { Function, Integer } from "@foundry/functions-api";
import { Airplane } from "@foundry/ontology-api";

export class MyFunctions {
    @Function()
    public getCapacity(airplane: Airplane): Integer {
        return airplane.capacity;
    }
}
import { Osdk } from "@osdk/client";
import { Integer } from "@osdk/functions";
import { Airplane } from "@ontology/sdk";

function getCapacity(airplane: Osdk.Instance<Airplane>): Integer {
    return airplane.capacity;
}

export default getCapacity;
from functions.api import function, Integer
from ontology_sdk.ontology.objects import Airplane

@function
def get_capacity(airplane: Airplane) -> Integer:
    return airplane.capacity

在 TypeScript v2 中,对对象类型的引用可作为 struct 参数字段使用。若要接收包含对象类型实例的 struct 或 struct 列表,请创建一个带有 Ontology SDK 对象类型字段的自定义类型输入。它可以与 Ontology 编辑 配合,支持诸如「从其它对象类型派生出多个对象类型实例」之类的工作流。

import { Osdk } from "@osdk/client";
import { Integer } from "@osdk/functions";
import { Airplane, Passenger, Ticket } from "@ontology/sdk";

type TicketEdit = Edits.Object<Ticket>

interface TicketInfo {
    airplane?: Osdk.Instance<Airplane>;
    passenger?: Osdk.Instance<Passenger>;
    seat?: String;
}

function createTickets(ticketInfo: TicketInfo[]): TicketEdit[] {
    const batch = createEditBatch<TicketEdit>(client);

    ticketInfo.forEach(i => batch.create(TicketEdit, {
        flightNumber: i.airplane.flightNumber,
        passengerName: i.passenger.name,
        seat: i.seat}))

    return batch.getEdits();
}

export default createTickets;

Object set

将对象集合传入或传出函数有两种方式:具体的对象集合(如数组),或对象集(object set)。

将对象数组传入函数,可以对一份具体的对象列表执行逻辑,代价是需要预先将所有对象加载到函数执行环境中。而对象集允许你执行筛选、周边检索和聚合操作,并且仅在请求时才加载最终结果。

我们建议使用对象集而非数组,因为对象集通常性能更好,且允许向函数传入超过 10,000 个对象。

下面的示例展示了如何在不将对象加载到内存的情况下筛选对象集,从而可将筛选后的对象集返回给应用的其他部分。

import { Function } from "@foundry/functions-api";
import { Airplane, ObjectSet } from "@foundry/ontology-api";

export class MyFunctions {
    @Function()
    public filterAircraft(aircraft: ObjectSet<Airplane>): ObjectSet<Airplane> {
        return aircraft.filter(a => a.capacity.range().gt(200));
    }
}
import { ObjectSet } from "@osdk/client";
import { Airplane } from "@ontology/sdk";

function filterAircraft(aircraft: ObjectSet<Airplane>): ObjectSet<Airplane> {
    return aircraft
        .where({
            capacity: {
                $gt: 200,
            }
        });
}

export default filterAircraft;
from functions.api import function
from ontology_sdk.ontology.objects import Airplane
from ontology_sdk.ontology.object_sets import AirplaneObjectSet

@function
def filter_aircraft(aircraft: AirplaneObjectSet) -> AirplaneObjectSet:
    return aircraft.where(Airplane.object_type.capacity > 200)

Interface

来自你的 Ontology 的接口类型,在 TypeScript v2 函数签名中既可作为输入也可作为输出。TypeScript v1 和 Python 不支持接口类型。

import { Osdk } from "@osdk/client";
import { Integer } from "@osdk/functions";
import { Person } from "@ontology/sdk";

function getAge(person: Osdk.Instance<Person>): Integer {
    return person.age;
}

export default getAge;

Interface object set

接口对象集在 TypeScript v2 函数签名中既可作为输入也可作为输出。

import { ObjectSet } from "@osdk/client";
import { Person } from "@ontology/sdk";

function filterPeople(people: ObjectSet<Person>): ObjectSet<Person> {
    return people
        .where({
            age: {
                $gt: 200,
            }
        });
}

export default filterPeople;

Ontology edit

除了编写从 Ontology 读取数据的函数,你还可以编写创建对象、编辑对象属性及对象间链接的函数。有关编辑函数工作方式的更多细节,请参阅概览页

要注册为编辑函数,TypeScript v1 函数需要在签名中声明 void 返回类型;而 TypeScript v2 和 Python 函数则需要显式返回一组 Ontology 编辑。

import { Edits, OntologyEditFunction } from "@foundry/functions-api";
import { Employee, LaptopRequest, Objects } from "@foundry/ontology-api";

export class MyFunctions {

    @Edits(Employee, LaptopRequest)
    @OntologyEditFunction()
    public assignEmployee(newEmployee: Employee, leadEmployee: Employee): void {

        const newLaptopRequest = Objects.create().laptopRequest(Date.now().toString());
        newLaptopRequest.employeeName = newEmployee.name;

        newEmployee.lead.set(leadEmployee);
    }
}
import { Client } from "@osdk/client";
import { createEditBatch, Edits } from "@osdk/functions";
import { Employee, LaptopRequest } from "@ontology/sdk";

type EmployeeEdit =
    | Edits.Object<Employee>
    | Edits.Object<LaptopRequest>
    | Edits.Link<Employee, "lead">;

function assignEmployee(
    client: Client,
    newEmployee: Osdk.Instance<Employee>,
    leadEmployee: Osdk.Instance<Employee>
): EmployeeEdit[] {

    const batch = createEditBatch<EmployeeEdit>(client);

    batch.create(LaptopRequest, {
        id: Date.now().toString(),
        employeeName: newEmployee.name,
    });
    batch.link(newEmployee, "lead", leadEmployee);

    return batch.getEdits();
}

export default assignEmployee;
from functions.api import function, OntologyEdit
from ontology_sdk import FoundryClient
from ontology_sdk.ontology.objects import Employee, LaptopRequest
from time import time

@function
def assign_employee(new_employee: Employee, lead_employee: Employee) -> list[OntologyEdit]:

    ontology_edits = FoundryClient().ontology.edits()

    new_laptop_request = ontology_edits.objects.LaptopRequest.create(str(int(time() * 1000)))
    new_laptop_request.employee_name = new_employee.name

    new_employee.lead.set(lead_employee)

    return ontology_edits.get_edits()

Attachment

import { Attachment, Function } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public loadAttachmentContents(attachment: Attachment): Promise<string> {
        return attachment.readAsync().then(blob => blob.text());
    }
}
import { Attachment } from "@osdk/functions";

function loadAttachmentContents(attachment: Attachment): Promise<string> {
    return attachment.fetchContents().then(response => response.text());
}

export default loadAttachmentContents;
from functions.api import function, Attachment

@function
def load_attachment_contents(attachment: Attachment) -> str:
    return attachment.read().getvalue().decode('utf-8')

Notification

Notification 类型可从函数返回,用于灵活配置平台中应发送的通知。例如,你可以编写一个函数,接收 User 和某个对象类型等参数,并返回一条带有配置好消息内容的 Notification。

  • Notification 由两个字段组成:ShortNotificationEmailNotificationContent
  • ShortNotification 表示通知的精简版本,会在 Foundry 平台内展示。它包含一个简短的 headingcontent,以及一组 Link
  • EmailNotificationContent 表示通知的富文本版本,可通过邮件外发。它包含一个 subject、由无头(headless)HTML 组成的 body,以及一组 Link
  • Link 具有面向用户的 labellinkTargetLinkTarget 可以是 URL、一个 OntologyObject,或 Foundry 中任意资源的 rid

有关如何使用 Notifications API 的示例,请参阅我们的指南

import {
    EmailNotificationContent,
    Function,
    Notification,
    ShortNotification,
} from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public buildNotification(): Notification {
        return Notification.builder()
            .shortNotification(ShortNotification.builder()
                .heading("Issue reminder")
                .content("Investigate this issue.")
                .build())
            .emailNotificationContent(EmailNotificationContent.builder()
                .subject("New issue")
                .body("hello")
                .build())
            .build();
    }
}
import {
    Notification
} from "@osdk/functions";

export default function buildNotification(): Notification {
    return {
        platformNotification: {
            heading: "Issue reminder",
            content: "Investigate this issue.",
            links: []
        },
        emailNotification: {
            subject: "New issue",
            body: "hello",
            links: []
        }
    };
}
from functions.api import function, Notification, PlatformNotification, EmailNotification

@function()
def buildNotification() -> Notification:
    return Notification(
        platform_notification=PlatformNotification(
            heading="Issue reminder",
            content="Investigate this issue.",
            links=[]
        ),
        email_notification=EmailNotification(
            subject="New issue",
            body="hello",
            links=[]
        ),
    )
5

媒体类型

媒体类型

要点:Media 类型用于承载媒体集里的文件。

Media

函数可以接收和返回媒体项。在 TypeScript v1 中使用 MediaItem 类型;在 TypeScript v2 和 Python 中,使用 Media 作为入参和出参类型。调用方可以将已有的 MediaReference(例如对象上的媒体属性)传入函数。下游使用者可利用返回值获取内容、获取元数据,或将其附加到另一个对象上。更多信息请参阅媒体指南。

import { Function, MediaItem } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public async echoMedia(media: MediaItem): Promise<string | undefined> {
        const mimeType: string = media.mimeType;
        // Fetch type-specific metadata (page count, dimensions, duration, and so on)
        const metadata = await media.getMetadataAsync();
        // Read the binary contents as a Blob
        const contents: Blob = await media.readAsync();
        // Narrow to a specialized subtype to call type-specific methods
        if (MediaItem.isDocument(media)) {
            const text = await media.extractTextAsync({ startPage: 0, endPage: 1 });
        } else if (MediaItem.isAudio(media)) {
            const transcript = await media.transcribeAsync();
        }
        return undefined;
    }
}
import type { Media } from "@osdk/client";

export default async function echoMedia(media: Media): Promise<Media> {
    // Get the underlying MediaReference
    const mediaReference = media.getMediaReference();
    // Fetch slim metadata: path, sizeBytes, mediaType
    const metadata = await media.fetchMetadata();
    // Fetch contents as a Response; call .blob() or .arrayBuffer() for bytes
    const response = await media.fetchContents();
    const contents = await response.blob();
    return media;
}
from foundry_sdk.v2.core.models import MediaReference
from functions.api import function, Media

@function
def echo_media(media: Media) -> Media:
    # Get the underlying MediaReference
    media_reference: MediaReference = media.get_media_reference()
    # Fetch slim metadata: path, size_bytes, media_type
    metadata = media.get_media_metadata()
    # Fetch type-specific metadata (page count, dimensions, duration, and more by type)
    full_metadata = media.get_media_full_metadata()
    # Fetch the binary contents as a BytesIO stream
    contents = media.get_media_content()
    return media
6

用户、组与主体

用户、组与主体

要点:User / Group / Principal,涉及权限与通知时会用到。

Principal 表示 Foundry 用户账户或用户组。这些类型可以传入函数,以便访问与用户或用户组关联的信息,例如用户组名称、用户的姓与名或电子邮件地址。所有 Principal 类型都从 @foundry/functions-api 包导出。

  • User 始终拥有 username,并可能拥有 firstNamelastNameemail。它还包含与 Principal 关联的所有字段。
  • Group 拥有一个 name。它还包含与 Principal 关联的所有字段。
  • Principal 可以是 UserGroup。你可以检查 type 字段来判断某个 PrincipalUser 还是 Group。除了 UserGroup 各自的字段外,Principal 还拥有 idrealm,以及一个 attributes 字典。

User

import { Function, User } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public getUserEmail(user: User): string {
        return user.email;
    }
}
import { UserId } from "@osdk/functions";
import { Users } from "@osdk/foundry.admin";
import { Client } from "@osdk/client";

export default function getUserEmail(client:Client, userId: UserId): string {
    const user = Users.get(client, userId)
    return user.email;
}
from functions.api import function, UserId
from foundry_sdk import FoundryClient
import foundry_sdk

@function()
def getUserEmail(user_id: UserId) -> string:
    client = FoundryClient(auth=foundry_sdk.UserTokenAuth(...), hostname="example.palantirfoundry.com")
    user = client.admin.User.get(user_id)
    return user.email

Group

import { Function, Group } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public getGroupName(group: Group): string {
        return group.name;
    }
}
import { GroupId } from "@osdk/functions";
import { Groups } from "@osdk/foundry.admin";
import { Client } from "@osdk/client";

export default function getGroupName(client: Client, groupId: GroupId): string {
    const group = Groups.get(client, groupId)
    return group.name;
}
from functions.api import function, GroupId
from foundry_sdk import FoundryClient
import foundry_sdk

@function()
def getGroupName(group_id: GroupId) -> string:
    client = FoundryClient(auth=foundry_sdk.UserTokenAuth(...), hostname="example.palantirfoundry.com")
    group = client.admin.Group.get(group_id)
    return group.name

Principal

import { Function, Principal } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public getPrincipalType(principal: Principal): string {

        switch (principal.type) {
            case "user":
                return "User";
            case "group":
                return "Group";
            default:
                return "Unknown";
        }
    }
}
import { GroupId, Principal, UserId } from "@osdk/functions";

export default async function getPrincipals(client: Client, userId: UserId, groupId: GroupId): Principal[] {
    return [{type: "user", id: userId}, {type: "group", id: groupId}];
}
from functions.api import Array, function, GroupId, Principal, UserId

@function()
def getPrincipals(user_id: UserId, group_id: GroupId) -> Array[Principal]:
    return [Principal.user(user_id), Principal.group(group_id)]
7

几何类型

几何类型

要点:GeoPoint 与 GeoShape,处理地理位置数据。

几何类型表示函数中的空间数据与地理形状。支持两种几何类型:

  • GeoPoint 表示具有经纬度坐标的单个地理点。
  • GeoShape 表示任意合法的 GeoJSON 几何,包括点(Points)、多边形(Polygons)、线(LineStrings)及其它形状。

这些类型遵循 GeoJSON 规范 ↗,可用于空间运算、地图绘制和地理分析。位置参数遵循 GeoJSON 规范中的「经度、纬度」顺序。

GeoPoint

下面的示例展示了如何创建并返回 GeoPoint。

import { Function, GeoPoint } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public createPoint(): GeoPoint {
        return GeoPoint.fromCoordinates({
            latitude: 37.7749,
            longitude: -22.4194
        });
    }
}
import { Point } from "@osdk/functions";

function createPoint(): Point {
    return {
        type: "Point",
        coordinates: [-22.4194, 37.7749]
    };
}

export default createPoint;
from functions.api import function, GeoPoint

@function
def create_point() -> GeoPoint:
    return GeoPoint(type="Point", coordinates=[-22.4194, 37.7749])

GeoShape

下面的示例展示了如何创建并返回 Polygon。

import { Function, Polygon, GeoPoint } from "@foundry/functions-api";

export class MyFunctions {
    @Function()
    public createPolygon(): Polygon {
        const ring: GeoPoint[] = [
            GeoPoint.fromCoordinates({ latitude: 37.8, longitude: -22.4 }),
            GeoPoint.fromCoordinates({ latitude: 37.8, longitude: -22.5 }),
            GeoPoint.fromCoordinates({ latitude: 37.7, longitude: -22.5 }),
            GeoPoint.fromCoordinates({ latitude: 37.7, longitude: -22.4 }),
            GeoPoint.fromCoordinates({ latitude: 37.8, longitude: -22.4 })
        ];
        return Polygon.fromLinearRings([ring]);
    }
}
import { Geometry } from "@osdk/functions";

function createPolygon(): Geometry {
    return {
        type: "Polygon",
        coordinates: [[
            [-22.4, 37.8],
            [-22.5, 37.8],
            [-22.5, 37.7],
            [-22.4, 37.7],
            [-22.4, 37.8]
        ]]
    };
}

export default createPolygon;
from functions.api import function, Polygon

@function
def create_polygon() -> Polygon:
    return Polygon(
        type="Polygon",
        coordinates=[[
            [-22.4, 37.8],
            [-22.5, 37.8],
            [-22.5, 37.7],
            [-22.4, 37.7],
            [-22.4, 37.8]
        ]])

Ontology 编辑函数 可以从 GeoJSON 字符串设置 geoshape 属性,但转换步骤因语言而异:

  • TypeScript v1: GeoShape.fromGeoJson() 接受已解析的 GeoJSON 几何或几何集合,因此传入前需先将字符串解析。
  • TypeScript v2: Geometry 就是一个普通的 GeoJSON 对象,因此无需转换函数,直接将解析后的值赋值即可。
  • Python: 每个具体几何类(如 PolygonLineString)都提供 from_geo_json() 方法,可直接接收 JSON 字符串。GeoShape 类型不提供此方法,因此请使用与实际几何相符的类。

下面的示例从 JSON 字符串设置 Region 对象的 geoshape 属性。

import { OntologyEditFunction, Edits, GeoShape } from "@foundry/functions-api";
import { Region } from "@foundry/ontology-api";

export class MyFunctions {
    @Edits(Region)
    @OntologyEditFunction()
    public updateBoundary(region: Region, boundary: string): void {
        region.boundary = GeoShape.fromGeoJson(JSON.parse(boundary));
    }
}
import { Region } from "@ontology/sdk";
import { Client, Osdk } from "@osdk/client";
import { createEditBatch, Edits, Geometry } from "@osdk/functions";

type RegionEdit = Edits.Object<Region>;

function updateBoundary(
    client: Client,
    region: Osdk.Instance<Region>,
    boundary: string
): RegionEdit[] {
    const batch = createEditBatch<RegionEdit>(client);

    batch.update(region, { boundary: JSON.parse(boundary) as Geometry });

    return batch.getEdits();
}

export default updateBoundary;
from functions.api import function, OntologyEdit, Polygon
from ontology_sdk import FoundryClient
from ontology_sdk.ontology.objects import Region

@function(edits=[Region])
def update_boundary(region: Region, boundary: str) -> list[OntologyEdit]:
    ontology_edits = FoundryClient().ontology.edits()

    editable_region = ontology_edits.objects.Region.edit(region)
    editable_region.boundary = Polygon.from_geo_json(boundary)

    return ontology_edits.get_edits()

延伸阅读 · 相关页面

按主题横向跳转,不必顺着目录一篇篇读。

常见问题速答 · FAQ

关于「函数类型参考手册」,读者最常问的几个问题。

标量类型是什么?
Boolean / String / 各种数字 / Date / Timestamp / Binary 等基础类型,以及必填与安全分级标记。
集合类型是什么?
List / Map / Set / Optional / 自定义结构体,用来描述复合数据。
聚合类型是什么?
Range 与二维、三维聚合,用于统计结果的表示。聚合类型可从函数返回,供平台的其它部分使用,例如 Workshop 中的图表。
本体类型是什么?
Object、Object set、Interface、Ontology edit、Attachment、Notification —— 业务函数的核心。