{"id":14988191,"url":"https://github.com/apache/skywalking-banyandb-java-client","last_synced_at":"2025-04-05T05:03:21.955Z","repository":{"id":38886994,"uuid":"401558592","full_name":"apache/skywalking-banyandb-java-client","owner":"apache","description":"The client implementation for SkyWalking BanyanDB in Java","archived":false,"fork":false,"pushed_at":"2025-03-27T03:55:20.000Z","size":484,"stargazers_count":20,"open_issues_count":0,"forks_count":10,"subscribers_count":37,"default_branch":"main","last_synced_at":"2025-04-03T04:17:07.093Z","etag":null,"topics":["apm","database","distributed-tracing","logging","metrics","observability","skywalking","time-series"],"latest_commit_sha":null,"homepage":"https://skywalking.apache.org/","language":"Java","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apache.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-31T03:18:08.000Z","updated_at":"2025-03-27T03:55:22.000Z","dependencies_parsed_at":"2024-01-25T23:05:31.212Z","dependency_job_id":"400a72a3-a3e5-4f06-b988-bbf784e2caeb","html_url":"https://github.com/apache/skywalking-banyandb-java-client","commit_stats":{"total_commits":96,"total_committers":7,"mean_commits":"13.714285714285714","dds":0.5416666666666667,"last_synced_commit":"e3f58db2107441ffa333d6949265935bc15ce2bd"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Fskywalking-banyandb-java-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Fskywalking-banyandb-java-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Fskywalking-banyandb-java-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apache%2Fskywalking-banyandb-java-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apache","download_url":"https://codeload.github.com/apache/skywalking-banyandb-java-client/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247149488,"owners_count":20891954,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apm","database","distributed-tracing","logging","metrics","observability","skywalking","time-series"],"created_at":"2024-09-24T14:16:16.361Z","updated_at":"2025-04-05T05:03:21.923Z","avatar_url":"https://github.com/apache.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"BanyanDB Java Client\n==========\n\n\u003cimg src=\"http://skywalking.apache.org/assets/logo.svg\" alt=\"Sky Walking logo\" height=\"90px\" align=\"right\" /\u003e\n\nThe client implement for SkyWalking BanyanDB in Java.\n\n[![GitHub stars](https://img.shields.io/github/stars/apache/skywalking.svg?style=for-the-badge\u0026label=Stars\u0026logo=github)](https://github.com/apache/skywalking)\n[![Twitter Follow](https://img.shields.io/twitter/follow/asfskywalking.svg?style=for-the-badge\u0026label=Follow\u0026logo=twitter)](https://twitter.com/AsfSkyWalking)\n\n[![CI/IT Tests](https://github.com/apache/skywalking-banyandb-java-client/workflows/CI%20AND%20IT/badge.svg?branch=main)](https://github.com/apache/skywalking-banyandb-java-client/actions?query=workflow%3ACI%2BAND%2BIT+event%3Aschedule+branch%main)\n\n# Usage\n\n## Create a client\n\nCreate a `BanyanDBClient` with the server's several addresses and then use `connect()` to establish a connection.\n\n```java\n// use `default` group\nBanyanDBClient client = new BanyanDBClient(\"banyandb.svc:17912\", \"10.0.12.9:17912\");\n// to send any request, a connection to the server must be estabilished\nclient.connect();\n```\n\nThese addresses are either IP addresses or DNS names. \n\nThe client will try to connect to the server in a round-robin manner. The client will periodically refresh the server\naddresses. The refresh interval can be configured by `refreshInterval` option.\n\nBesides, you may pass a customized options while building a `BanyanDBClient`. Supported\noptions are listed below,\n\n\n| Option                     | Description                                                          | Default                  |\n|----------------------------|----------------------------------------------------------------------|--------------------------|\n| maxInboundMessageSize      | Max inbound message size                                             | 1024 * 1024 * 50 (~50MB) |\n| deadline                   | Threshold of gRPC blocking query, unit is second                     | 30 (seconds)             |\n| refreshInterval            | Refresh interval for the gRPC channel, unit is second                | 30 (seconds)             |\n| resolveDNSInterval         | DNS resolve interval, unit is second                                 | 30 (minutes)             |\n| forceReconnectionThreshold | Threshold of force gRPC reconnection if network issue is encountered | 1                        |\n| forceTLS                   | Force use TLS for gRPC                                               | false                    |\n| sslTrustCAPath             | SSL: Trusted CA Path                                                 |                          |\n\n## Schema Management\n\n### Stream and index rules\n\n#### Define a Group\n```java\n// build a group sw_record for Stream with 2 shards and ttl equals to 3 days\nGroup g = Group.newBuilder().setMetadata(Metadata.newBuilder().setName(\"sw_record\"))\n            .setCatalog(Catalog.CATALOG_STREAM)\n            .setResourceOpts(ResourceOpts.newBuilder()\n                                         .setShardNum(2)\n                                         .setSegmentInterval(\n                                             IntervalRule.newBuilder()\n                                                         .setUnit(\n                                                             IntervalRule.Unit.UNIT_DAY)\n                                                         .setNum(\n                                                             1))\n                                         .setTtl(\n                                             IntervalRule.newBuilder()\n                                                         .setUnit(\n                                                             IntervalRule.Unit.UNIT_DAY)\n                                                         .setNum(\n                                                             3)))\n            .build();\nclient.define(g);\n```\n\nThen we may define a stream with customized configurations.\n\n#### Define a how-warm-cold Group\n\nHere illustrates how to use the lifecycle stages feature for hot-warm-cold data architecture:\n\n```java\n// build a group sw_record for Stream with hot-warm-cold lifecycle stages\nGroup g = Group.newBuilder().setMetadata(Metadata.newBuilder().setName(\"sw_record\"))\n            .setCatalog(Catalog.CATALOG_STREAM)\n            .setResourceOpts(ResourceOpts.newBuilder()\n                // Hot configuration\n                .setShardNum(3)\n                // Default segment interval (will be overridden by stages if defined)\n                .setSegmentInterval(\n                    IntervalRule.newBuilder()\n                        .setUnit(IntervalRule.Unit.UNIT_DAY)\n                        .setNum(1))\n                // Default TTL (will be overridden by stages if defined)\n                .setTtl(\n                    IntervalRule.newBuilder()\n                        .setUnit(IntervalRule.Unit.UNIT_DAY)\n                        .setNum(3))\n                // Define lifecycle stages (hot → warm → cold)\n                .addStages(LifecycleStage.newBuilder()\n                    .setName(\"warm\")\n                    .setShardNum(2) // Fewer shards\n                    .setSegmentInterval(IntervalRule.newBuilder()\n                        .setUnit(IntervalRule.Unit.UNIT_DAY)\n                        .setNum(1))\n                    .setTtl(IntervalRule.newBuilder()\n                        .setUnit(IntervalRule.Unit.UNIT_DAY)\n                        .setNum(7)) // Keep in warm for 7 days\n                    .setNodeSelector(\"hdd-nodes\") // Store on cheaper HDD nodes\n                    .build())\n                .addStages(LifecycleStage.newBuilder()\n                    .setName(\"cold\")\n                    .setShardNum(1) // Minimal shards for archived data\n                    .setSegmentInterval(IntervalRule.newBuilder()\n                        .setUnit(IntervalRule.Unit.UNIT_DAY)\n                        .setNum(7)) // Larger segments for cold data\n                    .setTtl(IntervalRule.newBuilder()\n                        .setUnit(IntervalRule.Unit.UNIT_DAY)\n                        .setNum(30)) // Keep in cold for 30 more days\n                    .setNodeSelector(\"archive-nodes\") // Store on archive nodes\n                    .setClose(true) // Close segments that are no longer live\n                    .build()))\n            .build();\nclient.define(g);\n```\n\nThis configuration creates a hot-warm-cold architecture where:\n- Hot stage: Data is stored on fast SSD nodes with many shards for 1 day, optimized for high query performance\n- Warm stage: Data moves to HDD nodes with fewer shards for 7 days, balanced between performance and cost\n- Cold stage: Data finally moves to archive nodes with minimal shards for 30 days, optimized for storage efficiency\n\nData automatically flows through these stages according to the defined TTLs. The total retention of data is 38 days (1+7+30).\n\n#### Define a Stream\n```java\n// build a stream trace with above group\nStream s = Stream.newBuilder()\n                 .setMetadata(Metadata.newBuilder()\n                                      .setGroup(\"sw_record\")\n                                      .setName(\"trace\"))\n                 .setEntity(Entity.newBuilder().addAllTagNames(\n                     Arrays.asList(\"service_id\", \"service_instance_id\", \"is_error\")))\n                 .addTagFamilies(TagFamilySpec.newBuilder()\n                                              .setName(\"data\")\n                                              .addTags(TagSpec.newBuilder()\n                                                              .setName(\"data_binary\")\n                                                              .setType(TagType.TAG_TYPE_DATA_BINARY)))\n                 .addTagFamilies(TagFamilySpec.newBuilder()\n                                              .setName(\"searchable\")\n                                              .addTags(TagSpec.newBuilder()\n                                                              .setName(\"trace_id\")\n                                                              .setType(TagType.TAG_TYPE_STRING))\n                                              .addTags(TagSpec.newBuilder()\n                                                              .setName(\"is_error\")\n                                                              .setType(TagType.TAG_TYPE_INT))\n                                              .addTags(TagSpec.newBuilder()\n                                                              .setName(\"service_id\")\n                                                              .setType(TagType.TAG_TYPE_STRING)\n                                                              .setIndexedOnly(true)))\n                 .build();\nclient.define(s);\n```\n\n#### Define a IndexRules\n```java\nIndexRule.Builder ir = IndexRule.newBuilder()\n                                     .setMetadata(Metadata.newBuilder()\n                                                          .setGroup(\"sw_record\")\n                                                          .setName(\"trace_id\"))\n                                     .addTags(\"trace_id\")\n                                     .setType(IndexRule.Type.TYPE_INVERTED)\n                                     .setAnalyzer(\"simple\");\nclient.define(ir.build());\n```\n\n#### Define a IndexRuleBinding\n```java\nIndexRuleBinding.Builder irb = IndexRuleBinding.newBuilder()\n                                                   .setMetadata(BanyandbCommon.Metadata.newBuilder()\n                                                                                       .setGroup(\"sw_record\")\n                                                                                       .setName(\"trace_binding\"))\n                                                   .setSubject(BanyandbDatabase.Subject.newBuilder()\n                                                                                       .setCatalog(\n                                                                                           BanyandbCommon.Catalog.CATALOG_STREAM)\n                                                                                       .setName(\"trace\"))\n                                                   .addAllRules(\n                                                       Arrays.asList(\"trace_id\"))\n                                                   .setBeginAt(TimeUtils.buildTimestamp(ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)))\n                                                   .setExpireAt(TimeUtils.buildTimestamp(DEFAULT_EXPIRE_AT));\nclient.define(irb.build());\n```\n\nFor the last line in the code block, a simple API (i.e. `BanyanDBClient.define(Stream)`) is used to define the schema of `Stream`.\nThe same works for `Measure` which will be demonstrated later.\n\n### Measure and index rules\n\n`Measure` can also be defined directly with `BanyanDBClient`,\n\n#### Define a Group\n```java\n// build a group sw_metrics for Measure with 2 shards and ttl equals to 7 days\nGroup g = Group.newBuilder().setMetadata(Metadata.newBuilder().setName(\"sw_metric\"))\n            .setCatalog(Catalog.CATALOG_MEASURE)\n            .setResourceOpts(ResourceOpts.newBuilder()\n                                         .setShardNum(2)\n                                         .setSegmentInterval(\n                                             IntervalRule.newBuilder()\n                                                         .setUnit(\n                                                             IntervalRule.Unit.UNIT_DAY)\n                                                         .setNum(\n                                                             1))\n                                         .setTtl(\n                                             IntervalRule.newBuilder()\n                                                         .setUnit(\n                                                             IntervalRule.Unit.UNIT_DAY)\n                                                         .setNum(\n                                                             7)))\n            .build();\nclient.define(g);\n```\n\n#### Define a Measure\n```java\n// create a new measure schema with an additional interval\n// the interval is used to specify how frequently to send a data point\nMeasure m = Measure.newBuilder()\n                   .setMetadata(Metadata.newBuilder()\n                                        .setGroup(\"sw_metric\")\n                                        .setName(\"service_cpm_minute\"))\n                   .setInterval(Duration.ofMinutes(1).format())\n                   .setEntity(Entity.newBuilder().addTagNames(\"entity_id\"))\n                   .addTagFamilies(\n                       TagFamilySpec.newBuilder()\n                                    .setName(\"default\")\n                                    .addTags(\n                                        TagSpec.newBuilder()\n                                               .setName(\"entity_id\")\n                                               .setType(\n                                                   TagType.TAG_TYPE_STRING))\n                                    .addTags(\n                                        TagSpec.newBuilder()\n                                               .setName(\"scope\")\n                                               .setType(\n                                                   TagType.TAG_TYPE_STRING)))\n                   .addFields(\n                       FieldSpec.newBuilder()\n                                .setName(\"total\")\n                                .setFieldType(\n                                    FieldType.FIELD_TYPE_INT)\n                                .setCompressionMethod(\n                                    CompressionMethod.COMPRESSION_METHOD_ZSTD)\n                                .setEncodingMethod(\n                                    EncodingMethod.ENCODING_METHOD_GORILLA))\n                   .addFields(\n                       FieldSpec.newBuilder()\n                                .setName(\"value\")\n                                .setFieldType(\n                                    FieldType.FIELD_TYPE_INT)\n                                .setCompressionMethod(\n                                    CompressionMethod.COMPRESSION_METHOD_ZSTD)\n                                .setEncodingMethod(\n                                    EncodingMethod.ENCODING_METHOD_GORILLA))\n                   .build();\n// define a measure, as we've mentioned above\nclient.define(m);\n```\n\nIf you want to create an `index_mode` `Measure`:\n\n```java\nMeasure m = Measure.newBuilder()\n                   .setMetadata(Metadata.newBuilder()\n                                        .setGroup(\"sw_metric\")\n                                        .setName(\"service_traffic\"))\n                   .setEntity(Entity.newBuilder().addTagNames(\"service_id\"))\n                   .setIndexMode(true)\n                   .addTagFamilies(\n                       TagFamilySpec.newBuilder()\n                                    .setName(\"default\")\n                                    .addTags(\n                                        TagSpec.newBuilder()\n                                               .setName(\"service_id\")\n                                               .setType(\n                                                   TagType.TAG_TYPE_STRING))\n                                    .addTags(\n                                        TagSpec.newBuilder()\n                                               .setName(\"layer\")\n                                               .setType(\n                                                   TagType.TAG_TYPE_STRING)))\n                    .build();\n// define a \"index_mode\" measure, as we've mentioned above\nclient.define(m);\n```\n\n### Define a Property\n\n```java\n// Define property schema\nBanyandbDatabase.Property propertyDef = \n   BanyandbDatabase.Property.newBuilder()\n        .setMetadata(Metadata.newBuilder()\n            .setGroup(\"default\")\n            .setName(\"ui_template\"))\n        .addTags(\n           TagSpec.newBuilder()\n               .setName(\"name\")\n               .setType(\n                   TagType.TAG_TYPE_STRING))\n        .build();\n\nclient.define(propertyDef);\n```\n\nFor more APIs usage, refer to test cases and API docs.\n\n## Query\n\n### Stream\n\nConstruct a `StreamQuery` instance with given time-range and other conditions.\n\n\u003e Note: time-range is left-inclusive and right-exclusive.\n\nFor example, \n\n```java\n// [begin, end) = [ now - 15min, now )\nInstant end = Instant.now();\nInstant begin = end.minus(15, ChronoUnit.MINUTES);\n// with stream schema, group=default, name=sw\nStreamQuery query = new StreamQuery(Lists.newArrayList(\"sw_record\"), \"trace\",\n        new TimestampRange(begin.toEpochMilli(), end.toEpochMilli()),\n        // projection tags which are indexed\n        ImmutableSet.of(\"state\", \"start_time\", \"duration\", \"trace_id\"));\n// search for all states\nquery.and(PairQueryCondition.StringQueryCondition.eq(\"searchable\", \"trace_id\" , \"1a60e0846817447eac4cd498eefd3743.1.17261060724190003\"));\n// set order by condition\nquery.setOrderBy(new AbstractQuery.OrderBy(AbstractQuery.Sort.DESC));\n// set projection for un-indexed tags\nquery.setDataProjections(ImmutableSet.of(\"data_binary\"));\n// send the query request\nclient.query(query);\n```\n\nAfter response is returned, `elements` can be fetched,\n\n```java\nStreamQueryResponse resp = client.query(query);\nList\u003cRowEntity\u003e entities = resp.getElements();\n```\n\nEvery item `RowEntity` in the list contains `elementId`, `timestamp` and tag families requested.\n\nThe `StreamQueryResponse`, `RowEntity`, `TagFamily` and `Tag` (i.e. `TagAndValue`) forms a hierarchical structure, where\nthe order of the tag families and containing tags, i.e. indexes of these objects in the List, follow the order specified \nin the projection condition we've used in the request.\n\nIf you want to trace the query, you can use `query.enableTrace()` to get the trace spans.\n\n```java\n// enable trace\nquery.enableTrace();\n// send the query request\nclient.query(query);\n```\n\nAfter response is returned, `trace` can be extracted,\n\n```java\n// send the query request\nStreamQueryResponse resp = client.queryStreams(query);\nTrace t = resp.getTrace();\n```\n\n### Measure\n\nFor `Measure`, it is similar to the `Stream`,\n\n```java\n// [begin, end) = [ now - 15min, now )\nInstant end = Instant.now();\nInstant begin = end.minus(15, ChronoUnit.MINUTES);\n// with stream schema, group=sw_metrics, name=service_instance_cpm_day\nMeasureQuery query = new MeasureQuery(Lists.newArrayList(\"sw_metrics\"), \"service_instance_cpm_day\",\n    new TimestampRange(begin.toEpochMilli(), end.toEpochMilli()),\n    ImmutableSet.of(\"id\", \"scope\", \"service_id\"),\n    ImmutableSet.of(\"total\"));\n// query max \"total\" with group by tag \"service_id\"\nquery.maxBy(\"total\", ImmutableSet.of(\"service_id\"));\n// use conditions\nquery.and(PairQueryCondition.StringQueryCondition.eq(\"default\", \"service_id\", \"abc\"));\n// send the query request\nclient.query(query);\n```\n\nAfter response is returned, `dataPoints` can be extracted,\n\n```java\nMeasureQueryResponse resp = client.query(query);\nList\u003cDataPoint\u003e dataPointList = resp.getDataPoints();\n```\n\nMeasure API supports `TopN`/`BottomN` search. The results or (grouped-)results are\nordered by the given `field`,\n\n```java\nMeasureQuery query = new MeasureQuery(\"sw_metrics\", \"service_instance_cpm_day\",\n        new TimestampRange(begin.toEpochMilli(), end.toEpochMilli()),\n        ImmutableSet.of(\"id\", \"scope\", \"service_id\"),\n        ImmutableSet.of(\"total\"));\nquery.topN(5, \"total\"); // bottomN\n```\n\nBesides, `limit` and `offset` are used to support pagination. `Tag`-based sort can also \nbe done to the final results,\n\n```java\nquery.limit(5);\nquery.offset(1);\nquery.orderBy(\"service_id\", Sort.DESC);\n```\n\nIf you want to trace the query, you can use `query.enableTrace()` to get the trace spans.\n\n```java\n// enable trace\nquery.enableTrace();\n// send the query request\nclient.query(query);\n```\n\nAfter response is returned, `trace` can be extracted,\n\n```java\n// send the query request\nMeasureQueryResponse resp = client.query(query);\nTrace trace = resp.getTrace();\n```\n\n### Property\n\nQuery properties:\n\n```java\nBanyandbProperty.QueryRequest queryRequest = new PropertyQuery(Lists.newArrayList(\"default\"), \"ui_template\", ImmutableSet.of(\"name\")).build();\nBanyandbProperty.QueryResponse queryResponse = client.query(queryRequest);\n```\n\nQuery properties based on ID:\n\n```java\nBanyandbProperty.QueryRequest queryRequest = new PropertyQuery(Lists.newArrayList(\"default\"), \"ui_template\", ImmutableSet.of(\"name\")).id(\"dashboard-1\").build();\nBanyandbProperty.QueryResponse queryResponse = client.query(queryRequest);\n```\n\nQuery properties based on tags:\n\n```java\nPropertyQuery pQuery = new PropertyQuery(Lists.newArrayList(\"default\"), \"ui_template\", ImmutableSet.of(\"name\"));\n pQuery.criteria(PairQueryCondition.StringQueryCondition.eq(\"name\", \"foo\"));\nBanyandbProperty.QueryResponse resp = client.query(pQuery.build());\n```\n\n### Criteria\n\nBoth `StreamQuery` and `MeausreQuery` support the `criteria` flag to filter data.\n`criteria` supports logical expressions and binary condition operations.\n\n#### Example of `criteria`\n\nThe expression `(a=1 and b = 2) or (a=4 and b=5)` could use below operations to support.\n\n```java\nquery.criteria(Or.create(\n                And.create(\n                        PairQueryCondition.LongQueryCondition.eq(\"a\", 1L),\n                        PairQueryCondition.LongQueryCondition.eq(\"b\", 1L)),\n                And.create(\n                        PairQueryCondition.LongQueryCondition.eq(\"a\", 4L),\n                        PairQueryCondition.LongQueryCondition.eq(\"b\", 5L)\n                )\n        ));\n```\nThe execution order of conditions is from the inside to outside. The deepest condition\nwill get executed first.\n\nThe client also provides syntactic sugar for using `and` or `or` methods.\nThe `criteria` method has a higher priority, overwriting these sugar methods.\n\n\u003e Caveat: Sugar methods CAN NOT handle nested query. `criteria` is the canonical\n\u003e method to take such tasks as above example shows.\n\n#### Example of `and`\n\nWhen filtering data matches all the conditions, the query can append several `and`:\n```java\nquery.and(PairQueryCondition.LongQueryCondition.eq(\"state\", 1L))\n        .and(PairQueryCondition.StringQueryCondition.eq(\"service_id\", serviceId))\n        .and(PairQueryCondition.StringQueryCondition.eq(\"service_instance_id\", serviceInstanceId))\n        .and(PairQueryCondition.StringQueryCondition.match(\"endpoint_id\", endpointId))\n        .and(PairQueryCondition.LongQueryCondition.ge(\"duration\", minDuration))\n        .and(PairQueryCondition.LongQueryCondition.le(\"duration\", maxDuration))\n```\n\n#### Example of `or`\n\nWhen gathering all data matches any of the conditions, the query can combine a series of `or`:\n\n```java\nsegmentIds.forEach(id -\u003e query.or(PairQueryCondition.LongQueryCondition.eq(\"segment_id\", id)))\n```\n\n## Write\n\n### Stream\n\nSince grpc bidi streaming is used for write protocol, build a `StreamBulkWriteProcessor` which would handle back-pressure for you.\nAdjust `maxBulkSize`, `flushInterval`, `concurrency` and `timeout` of the consumer in different scenarios to meet requirements.\n\n```java\n// build a StreamBulkWriteProcessor from client\nStreamBulkWriteProcessor streamBulkWriteProcessor = client.buildStreamWriteProcessor(maxBulkSize, flushInterval, concurrency, timeout);\n```\n\nThe `StreamBulkWriteProcessor` is thread-safe and thus can be used across threads.\nWe highly recommend you to reuse it.\n\nThe procedure of constructing `StreamWrite` entity must comply with the schema of the stream, e.g.\nthe order of tags must exactly be the same with that defined in the schema.\nAnd the non-existing tags must be fulfilled (with NullValue) instead of compacting all non-null tag values.\n\n```java\nStreamWrite streamWrite = client.createStreamWrite(\"default\", \"sw\", segmentId, now.toEpochMilli())\n    .tag(\"data_binary\", Value.binaryTagValue(byteData))\n    .tag(\"trace_id\", Value.stringTagValue(traceId)) // 0\n    .tag(\"state\", Value.longTagValue(state)) // 1\n    .tag(\"service_id\", Value.stringTagValue(serviceId)) // 2\n    .tag(\"service_instance_id\", Value.stringTagValue(serviceInstanceId)) // 3\n    .tag(\"endpoint_id\", Value.stringTagValue(endpointId)) // 4\n    .tag(\"duration\", Value.longTagValue(latency)) // 5\n    .tag(\"http.method\", Value.stringTagValue(null)) // 6\n    .tag(\"status_code\", Value.stringTagValue(httpStatusCode)) // 7\n    .tag(\"db.type\", Value.stringTagValue(dbType)) // 8\n    .tag(\"db.instance\", Value.stringTagValue(dbInstance)) // 9\n    .tag(\"mq.broker\", Value.stringTagValue(broker)) // 10\n    .tag(\"mq.topic\", Value.stringTagValue(topic)) // 11\n    .tag(\"mq.queue\", Value.stringTagValue(queue)); // 12\n\nCompletableFuture\u003cVoid\u003e f = streamBulkWriteProcessor.add(streamWrite);\nf.get(10, TimeUnit.SECONDS);\n```\n\n### Measure\n\nThe writing procedure for `Measure` is similar to the above described process and leverages the bidirectional streaming of gRPC,\n\n```java\n// build a MeasureBulkWriteProcessor from client\nMeasureBulkWriteProcessor measureBulkWriteProcessor = client.buildMeasureWriteProcessor(maxBulkSize, flushInterval, concurrency, timeout);\n```\n\nA `BulkWriteProcessor` is created by calling `buildMeasureWriteProcessor`. Then build the `MeasureWrite` object and send with bulk processor,\n\n```java\nInstant now = Instant.now();\nMeasureWrite measureWrite = client.createMeasureWrite(\"sw_metric\", \"service_cpm_minute\", now.toEpochMilli());\n    measureWrite.tag(\"id\", TagAndValue.stringTagValue(\"1\"))\n    .tag(\"entity_id\", TagAndValue.stringTagValue(\"entity_1\"))\n    .field(\"total\", TagAndValue.longFieldValue(100))\n    .field(\"value\", TagAndValue.longFieldValue(1));\n\nCompletableFuture\u003cVoid\u003e f = measureBulkWriteProcessor.add(measureWrite);\nf.get(10, TimeUnit.SECONDS);\n```\n\n### Property\n\nUnlike `Stream` and `Measure`, `Property` is a single write operation. The `Property` object is created and sent to the server.\n\n```java\n// Apply a property (create or update)\nProperty property = Property.newBuilder()\n    .setMetadata(\n        BanyandbCommon.Metadata.newBuilder()\n            .setGroup(\"default\")\n            .setName(\"sw\").build())\n    .setId(\"dashboard-1\")\n    .addTags(Tag.newBuilder().setKey(\"name\").setValue(\n        TagValue.newBuilder().setStr(Str.newBuilder().setValue(\"hello\"))))\n    .build();\n\nApplyResponse response = client.apply(property);\n```\n\nYou can also apply with a specific strategy:\n\n```java\n// Apply with merge strategy\nApplyResponse response = client.apply(property, Strategy.STRATEGY_MERGE);\n```\n\n## Delete\n\n### Stream and Measure\n\nThe `Stream` and `Measure` are deleted by the TTL mechanism. You can set the TTL when defining the group schema.\n\n### Property\n\nDelete a property:\n\n```java\n// Delete a property\nDeleteResponse deleteResponse = client.deleteProperty(\"default\", \"ui_template\", \"dashboard-1\");\n```\n\n# Compiling project\n\u003e ./mvnw clean package\n\n# Code of conduct\nThis project adheres to the Contributor Covenant [code of conduct](https://www.apache.org/foundation/policies/conduct). By participating, you are expected to uphold this code.\nPlease follow the [REPORTING GUIDELINES](https://www.apache.org/foundation/policies/conduct#reporting-guidelines) to report unacceptable behavior.\n\n# Contact Us\n* Mail list: **dev@skywalking.apache.org**. Mail to `dev-subscribe@skywalking.apache.org`, follow the reply to subscribe the mail list.\n* Send `Request to join SkyWalking slack` mail to the mail list(`dev@skywalking.apache.org`), we will invite you in.\n* Twitter, [ASFSkyWalking](https://twitter.com/ASFSkyWalking)\n* QQ Group: 901167865(Recommended), 392443393\n* [bilibili B站 视频](https://space.bilibili.com/390683219)\n\n# License\n[Apache 2.0 License.](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapache%2Fskywalking-banyandb-java-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapache%2Fskywalking-banyandb-java-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapache%2Fskywalking-banyandb-java-client/lists"}