Repository: googleapis/java-bigtable-hbase (java)

Issue:
ExportJob has excessive RAM usage
When running the beam export job:

```
java -jar bigtable-beam-import-2.14.1-shaded.jar export --runner=dataflow ...
```

![image](https://github.com/googleapis/java-bigtable-hbase/assets/292519/f72c72f5-1094-4c0f-b20b-dbf636c7ac71)

Beam defaults to 1MB for streaming jobs to address memory usage, but doesn't for batch jobs. In addition, the {Spark,Flink}JobServerDriver do the same thing, setting it to 1MB:

https://github.com/apache/beam/pull/9647

This has the potential impact of reducing the speed of single file uploads, but in general, this export job does many in parallel.

Pull request description:
fix: set buffer size to 8MB for export jobs to reduce ram usage
Beam defaults to 1MB for streaming jobs to address memory usage, but doesn't for batch jobs. In addition, the {Spark,Flink}JobServerDriver do the same thing, setting it to 1MB:

https://github.com/apache/beam/pull/9647

In some internal benchmarks, 8M has been shown to not incur a cost on the throughput per worker that 1M has for the export job, so we are opting to set it to 8M.

Fixes #4365 ☕️


Patch:
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/FamilyFilterAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/FamilyFilterAdapter.java
index 1fd0596d3..1e225e8fa 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/FamilyFilterAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/FamilyFilterAdapter.java
@@ -55,6 +55,11 @@ public class FamilyFilterAdapter extends TypedFilterAdapterBase<FamilyFilter> {
       throw new IllegalStateException("Comparator cannot be null");
     } else if (comparator instanceof RegexStringComparator) {
       family = Bytes.toString(comparator.getValue());
+      // HBase regex matching is unanchored, while Bigtable requires a full string match
+      // To align the two, surround the user regex with wildcards
+      if (!family.isEmpty()) {
+        family = ".*" + family + ".*";
+      }
     } else if (comparator instanceof BinaryComparator) {
       ByteString quotedRegularExpression =
           ReaderExpressionHelper.quoteRegularExpression(comparator.getValue());
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/QualifierFilterAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/QualifierFilterAdapter.java
index 8f4bc5b4c..5c0c15f74 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/QualifierFilterAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/QualifierFilterAdapter.java
@@ -113,6 +113,11 @@ public class QualifierFilterAdapter extends TypedFilterAdapterBase<QualifierFilt
   private static Filter adaptRegexStringComparator(
       CompareOp compareOp, RegexStringComparator comparator) {
     String pattern = FilterAdapterHelper.extractRegexPattern(comparator);
+    // HBase regex matching is unanchored, while Bigtable requires a full string match
+    // To align the two, surround the user regex with wildcards
+    if (!pattern.isEmpty()) {
+      pattern = "\\C*" + pattern + "\\C*";
+    }
     switch (compareOp) {
       case EQUAL:
         return FILTERS.qualifier().regex(pattern);
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/RowFilterAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/RowFilterAdapter.java
index 27ff2129a..07fddd6f2 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/RowFilterAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/RowFilterAdapter.java
@@ -58,7 +58,17 @@ public class RowFilterAdapter
     if (comparator == null) {
       throw new IllegalStateException("Comparator cannot be null");
     } else if (comparator instanceof RegexStringComparator) {
-      regexValue = ByteString.copyFrom(comparator.getValue());
+      // HBase regex matching is unanchored, while Bigtable requires a full string match
+      // To align the two, surround the user regex with wildcards
+      if (comparator.getValue().length > 0) {
+        regexValue =
+            ByteString.copyFromUtf8("\\C*")
+                .concat(ByteString.copyFrom(comparator.getValue()))
+                .concat(ByteString.copyFromUtf8("\\C*"));
+      } else {
+        regexValue = ByteString.EMPTY;
+      }
+
     } else if (comparator instanceof BinaryComparator) {
       regexValue = ReaderExpressionHelper.quoteRegularExpression(comparator.getValue());
     } else {
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/ValueFilterAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/ValueFilterAdapter.java
index e8621c92f..292a5e68d 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/ValueFilterAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/filters/ValueFilterAdapter.java
@@ -116,6 +116,11 @@ public class ValueFilterAdapter extends TypedFilterAdapterBase<ValueFilter> {
     String pattern = FilterAdapterHelper.extractRegexPattern(comparator);
     switch (compareOp) {
       case EQUAL:
+        // HBase regex matching is unanchored, while Bigtable requires a full string match
+        // To align the two, surround the user regex with wildcards
+        if (!pattern.isEmpty()) {
+          pattern = "\\C*" + pattern + "\\C*";
+        }
         return FILTERS.value().regex(pattern);
         // No-ops are always filtered out.
         // See:
diff --git a/bigtable-dataflow-parent/bigtable-beam-import/src/main/java/com/google/cloud/bigtable/beam/sequencefiles/ExportJob.java b/bigtable-dataflow-parent/bigtable-beam-import/src/main/java/com/google/cloud/bigtable/beam/sequencefiles/ExportJob.java
index 0c7ef060b..740466b05 100644
--- a/bigtable-dataflow-parent/bigtable-beam-import/src/main/java/com/google/cloud/bigtable/beam/sequencefiles/ExportJob.java
+++ b/bigtable-dataflow-parent/bigtable-beam-import/src/main/java/com/google/cloud/bigtable/beam/sequencefiles/ExportJob.java
@@ -23,6 +23,7 @@ import java.io.Serializable;
 import org.apache.beam.sdk.Pipeline;
 import org.apache.beam.sdk.PipelineResult;
 import org.apache.beam.sdk.extensions.gcp.options.GcpOptions;
+import org.apache.beam.sdk.extensions.gcp.options.GcsOptions;
 import org.apache.beam.sdk.io.DefaultFilenamePolicy;
 import org.apache.beam.sdk.io.FileSystems;
 import org.apache.beam.sdk.io.Read;
@@ -95,7 +96,10 @@ import org.apache.hadoop.io.serializer.WritableSerialization;
  */
 @InternalExtensionOnly
 public class ExportJob {
-  public interface ExportOptions extends GcpOptions {
+
+  static final int GCS_UPLOAD_BUFFER_SIZE_BYTES_DEFAULT = 8388608;
+
+  public interface ExportOptions extends GcpOptions, GcsOptions {
     @Description("This Bigtable App Profile id.")
     ValueProvider<String> getBigtableAppProfileId();
 
@@ -182,6 +186,9 @@ public class ExportJob {
 
     ExportOptions opts =
         PipelineOptionsFactory.fromArgs(args).withValidation().as(ExportOptions.class);
+    if (opts.getGcsUploadBufferSizeBytes() == null) {
+      opts.setGcsUploadBufferSizeBytes(GCS_UPLOAD_BUFFER_SIZE_BYTES_DEFAULT);
+    }
 
     Pipeline pipeline = buildPipeline(opts);
 


Test patch:
diff --git a/bigtable-client-core-parent/bigtable-hbase-integration-tests-common/src/test/java/com/google/cloud/bigtable/hbase/AbstractTestFilters.java b/bigtable-client-core-parent/bigtable-hbase-integration-tests-common/src/test/java/com/google/cloud/bigtable/hbase/AbstractTestFilters.java
index 507d58ffa..deae3d8ef 100644
--- a/bigtable-client-core-parent/bigtable-hbase-integration-tests-common/src/test/java/com/google/cloud/bigtable/hbase/AbstractTestFilters.java
+++ b/bigtable-client-core-parent/bigtable-hbase-integration-tests-common/src/test/java/com/google/cloud/bigtable/hbase/AbstractTestFilters.java
@@ -18,6 +18,7 @@ package com.google.cloud.bigtable.hbase;
 import static com.google.cloud.bigtable.hbase.test_env.SharedTestEnvRule.COLUMN_FAMILY;
 import static com.google.cloud.bigtable.hbase.test_env.SharedTestEnvRule.COLUMN_FAMILY2;
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -32,6 +33,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.UUID;
 import org.apache.commons.lang.RandomStringUtils;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellUtil;
@@ -2297,6 +2299,97 @@ public abstract class AbstractTestFilters extends AbstractTest {
         actualKey);
   }
 
+  /**
+   * Bigtable & HBase have different semantics for regexes - HBase matches are unachored and allow
+   * for the regex to match anywhere in the string. While Bigtable requires a full string match.
+   */
+  @Test
+  public void testPartialRegexMatches() throws Exception {
+    Table table = getDefaultTable();
+    String keyRoot = UUID.randomUUID().toString();
+    String key = "prefix-" + keyRoot + "-suffix";
+    String family = new String(COLUMN_FAMILY);
+    String familyRoot = family.substring(3, family.length() - 3);
+    String qualifierRoot = "my-qualifier";
+    String qualifier = "prefix-" + qualifierRoot + "-suffix";
+    String valueRoot = "my-value";
+    String value = "prefix-" + valueRoot + "-suffix";
+
+    table.put(
+        new Put(key.getBytes()).addColumn(COLUMN_FAMILY, qualifier.getBytes(), value.getBytes()));
+
+    // Partial regexes that match the root of the value with single char matchers to make sure it
+    // doesnt use a literal optimization
+    List<Filter> filters =
+        Arrays.asList(
+            new RowFilter(CompareOp.EQUAL, new RegexStringComparator("." + keyRoot + ".")),
+            new FamilyFilter(CompareOp.EQUAL, new RegexStringComparator("." + familyRoot + ".")),
+            new QualifierFilter(
+                CompareOp.EQUAL, new RegexStringComparator("." + qualifierRoot + ".")),
+            new ValueFilter(CompareOp.EQUAL, new RegexStringComparator("." + valueRoot + ".")));
+
+    for (Filter filter : filters) {
+      try (ResultScanner scanner =
+          table.getScanner(new Scan().withStartRow(key.getBytes()).setLimit(1).setFilter(filter))) {
+        assertWithMessage("Filter with partial regex: " + filter + " yielded no results")
+            .that(scanner)
+            .isNotEmpty();
+      }
+    }
+
+    // Make sure that explicitly anchored regexes still work
+    List<Filter> anchoredRegex =
+        Arrays.asList(
+            new RowFilter(CompareOp.EQUAL, new RegexStringComparator("^" + key)),
+            new RowFilter(CompareOp.EQUAL, new RegexStringComparator(key + "$")),
+            new RowFilter(CompareOp.EQUAL, new RegexStringComparator("^" + key + "$")),
+            new FamilyFilter(CompareOp.EQUAL, new RegexStringComparator("^" + family)),
+            new FamilyFilter(CompareOp.EQUAL, new RegexStringComparator(family + "$")),
+            new FamilyFilter(CompareOp.EQUAL, new RegexStringComparator("^" + family + "$")),
+            new QualifierFilter(CompareOp.EQUAL, new RegexStringComparator("^" + qualifier + "$")),
+            new QualifierFilter(CompareOp.EQUAL, new RegexStringComparator("^" + qualifier)),
+            new QualifierFilter(CompareOp.EQUAL, new RegexStringComparator("^" + qualifier)),
+            new ValueFilter(CompareOp.EQUAL, new RegexStringComparator("^" + value + "$")),
+            new ValueFilter(CompareOp.EQUAL, new RegexStringComparator("^" + value)),
+            new ValueFilter(CompareOp.EQUAL, new RegexStringComparator(value + "$")));
+
+    for (Filter filter : anchoredRegex) {
+      try (ResultScanner scanner =
+          table.getScanner(new Scan().withStartRow(key.getBytes()).setLimit(1).setFilter(filter))) {
+        assertWithMessage("Filter with full regex: " + filter + " yielded no results")
+            .that(scanner)
+            .isNotEmpty();
+      }
+    }
+
+    // Make sure that explicitly anchored partial regexes dont overmatch
+    List<Filter> anchoredPartialRegex =
+        Arrays.asList(
+            new RowFilter(CompareOp.EQUAL, new RegexStringComparator("^" + keyRoot + "$")),
+            new RowFilter(CompareOp.EQUAL, new RegexStringComparator("^" + keyRoot)),
+            new RowFilter(CompareOp.EQUAL, new RegexStringComparator(keyRoot + "$")),
+            new FamilyFilter(CompareOp.EQUAL, new RegexStringComparator("^" + familyRoot + " $")),
+            new FamilyFilter(CompareOp.EQUAL, new RegexStringComparator("^" + familyRoot)),
+            new FamilyFilter(CompareOp.EQUAL, new RegexStringComparator(familyRoot + " $")),
+            new QualifierFilter(
+                CompareOp.EQUAL, new RegexStringComparator("^" + qualifierRoot + "$")),
+            new QualifierFilter(CompareOp.EQUAL, new RegexStringComparator("^" + qualifierRoot)),
+            new QualifierFilter(CompareOp.EQUAL, new RegexStringComparator(qualifierRoot + "$")),
+            new ValueFilter(CompareOp.EQUAL, new RegexStringComparator("^" + valueRoot + "$")),
+            new ValueFilter(CompareOp.EQUAL, new RegexStringComparator("^" + valueRoot)),
+            new ValueFilter(CompareOp.EQUAL, new RegexStringComparator(valueRoot + "$")));
+
+    for (Filter filter : anchoredPartialRegex) {
+      try (ResultScanner scanner =
+          table.getScanner(new Scan().withStartRow(key.getBytes()).setLimit(1).setFilter(filter))) {
+        assertWithMessage(
+                "Filter with anchored partial regex: " + filter + " yielded unpexpected results")
+            .that(scanner)
+            .isEmpty();
+      }
+    }
+  }
+
   private final String toFuzzyKeyString(byte[] bytes) {
     StringBuilder sb = new StringBuilder("[");
     String prefix = "";
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestFamilyFilterAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestFamilyFilterAdapter.java
index 00d002629..4d9939660 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestFamilyFilterAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestFamilyFilterAdapter.java
@@ -15,6 +15,8 @@
  */
 package com.google.cloud.bigtable.hbase.adapters.filters;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.google.bigtable.v2.RowFilter;
 import com.google.cloud.bigtable.hbase.adapters.read.ReaderExpressionHelper;
 import com.google.protobuf.ByteString;
@@ -45,13 +47,16 @@ public class TestFamilyFilterAdapter {
 
   @Test
   public void testAdapt_RegexAndEquals() throws IOException {
-    String regexp = "^.*hello world.*$";
+    String regexp = "^hello world[?!]$";
     RegexStringComparator comparator = new RegexStringComparator(regexp);
     org.apache.hadoop.hbase.filter.RowFilter filter =
         new org.apache.hadoop.hbase.filter.RowFilter(CompareFilter.CompareOp.EQUAL, comparator);
-    Assert.assertEquals(
-        RowFilter.newBuilder().setRowKeyRegexFilter(ByteString.copyFrom(regexp.getBytes())).build(),
-        adapter.adapt(context, filter).toProto());
+    assertThat(adapter.adapt(context, filter).toProto())
+        .isEqualTo(
+            RowFilter.newBuilder()
+                // user regex needs to be wrapped in wildcards to
+                .setRowKeyRegexFilter(ByteString.copyFrom(("\\C*" + regexp + "\\C*").getBytes()))
+                .build());
   }
 
   @Test
@@ -74,9 +79,11 @@ public class TestFamilyFilterAdapter {
     RegexStringComparator comparator = new RegexStringComparator(regexp);
     org.apache.hadoop.hbase.filter.RowFilter filter =
         new org.apache.hadoop.hbase.filter.RowFilter(CompareFilter.CompareOp.EQUAL, comparator);
-    Assert.assertEquals(
-        RowFilter.newBuilder().setRowKeyRegexFilter(ByteString.copyFrom(regexp.getBytes())).build(),
-        adapter.adapt(context, filter).toProto());
+    assertThat(adapter.adapt(context, filter).toProto())
+        .isEqualTo(
+            RowFilter.newBuilder()
+                .setRowKeyRegexFilter(ByteString.copyFrom(regexp.getBytes()))
+                .build());
   }
 
   @Test
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestQualifierFilterAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestQualifierFilterAdapter.java
index 06c16671e..fa99293da 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestQualifierFilterAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestQualifierFilterAdapter.java
@@ -18,6 +18,7 @@ package com.google.cloud.bigtable.hbase.adapters.filters;
 import static com.google.cloud.bigtable.data.v2.models.Filters.FILTERS;
 
 import com.google.cloud.bigtable.data.v2.models.Filters;
+import com.google.common.truth.Truth;
 import com.google.protobuf.ByteString;
 import java.io.IOException;
 import org.apache.hadoop.hbase.client.Scan;
@@ -28,7 +29,6 @@ import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
 import org.apache.hadoop.hbase.filter.QualifierFilter;
 import org.apache.hadoop.hbase.filter.RegexStringComparator;
 import org.apache.hadoop.hbase.util.Bytes;
-import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -51,7 +51,7 @@ public class TestQualifierFilterAdapter {
       throws IOException {
     QualifierFilter filter = new QualifierFilter(op, comparable);
     Filters.Filter actualFilter = adapter.adapt(scanWithOnFamilyScanContext, filter);
-    Assert.assertEquals(expectedFilter.toProto(), actualFilter.toProto());
+    Truth.assertThat(actualFilter.toProto()).isEqualTo(expectedFilter.toProto());
   }
 
   @Test
@@ -112,6 +112,6 @@ public class TestQualifierFilterAdapter {
     assertAdaptedForm(
         new RegexStringComparator(pattern),
         CompareOp.EQUAL,
-        FILTERS.qualifier().regex(ByteString.copyFromUtf8(pattern)));
+        FILTERS.qualifier().regex(ByteString.copyFromUtf8("\\C*" + pattern + "\\C*")));
   }
 }
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestRowFilterAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestRowFilterAdapter.java
index 2d89164ce..49c80d48f 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestRowFilterAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestRowFilterAdapter.java
@@ -16,6 +16,7 @@
 package com.google.cloud.bigtable.hbase.adapters.filters;
 
 import static com.google.cloud.bigtable.data.v2.models.Filters.FILTERS;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.cloud.bigtable.hbase.adapters.read.ReaderExpressionHelper;
 import com.google.protobuf.ByteString;
@@ -50,8 +51,8 @@ public class TestRowFilterAdapter {
     RegexStringComparator comparator = new RegexStringComparator(regexp);
     org.apache.hadoop.hbase.filter.RowFilter filter =
         new org.apache.hadoop.hbase.filter.RowFilter(CompareFilter.CompareOp.EQUAL, comparator);
-    Assert.assertEquals(
-        FILTERS.key().regex(regexp).toProto(), adapter.adapt(context, filter).toProto());
+    assertThat(adapter.adapt(context, filter).toProto())
+        .isEqualTo(FILTERS.key().regex("\\C*" + regexp + "\\C*").toProto());
   }
 
   @Test
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestValueFilterAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestValueFilterAdapter.java
index 3e4ee011b..af4689eeb 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestValueFilterAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/filters/TestValueFilterAdapter.java
@@ -16,6 +16,7 @@
 package com.google.cloud.bigtable.hbase.adapters.filters;
 
 import static com.google.cloud.bigtable.data.v2.models.Filters.FILTERS;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.cloud.bigtable.data.v2.models.Filters;
 import com.google.cloud.bigtable.hbase.adapters.read.ReaderExpressionHelper;
@@ -29,7 +30,6 @@ import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
 import org.apache.hadoop.hbase.filter.RegexStringComparator;
 import org.apache.hadoop.hbase.filter.ValueFilter;
 import org.apache.hadoop.hbase.util.Bytes;
-import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -110,7 +110,9 @@ public class TestValueFilterAdapter {
   public void testRegexValueFilter() throws IOException {
     String pattern = "Foo\\d+";
     assertAdaptedForm(
-        new RegexStringComparator(pattern), CompareOp.EQUAL, FILTERS.value().regex(pattern));
+        new RegexStringComparator(pattern),
+        CompareOp.EQUAL,
+        FILTERS.value().regex("\\C*" + pattern + "\\C*"));
   }
 
   private void assertAdaptedForm(
@@ -118,6 +120,6 @@ public class TestValueFilterAdapter {
       throws IOException {
     ValueFilter filter = new ValueFilter(op, comparable);
     Filters.Filter actualFilter = adapter.adapt(emptyScanContext, filter);
-    Assert.assertEquals(expectedFilter.toProto(), actualFilter.toProto());
+    assertThat(actualFilter.toProto()).isEqualTo(expectedFilter.toProto());
   }
 }
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/read/TestGetAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/read/TestGetAdapter.java
index 7c9ca1407..7d4d5e5a9 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/read/TestGetAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/read/TestGetAdapter.java
@@ -16,6 +16,7 @@
 package com.google.cloud.bigtable.hbase.adapters.read;
 
 import static com.google.cloud.bigtable.data.v2.models.Filters.FILTERS;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.cloud.bigtable.data.v2.internal.RequestContext;
 import com.google.cloud.bigtable.data.v2.models.Filters;
@@ -182,12 +183,12 @@ public class TestGetAdapter {
 
     Filters.Filter actualFilter = getAdapter.buildFilter(get);
 
-    Assert.assertEquals(
-        FILTERS
-            .chain()
-            .filter(FILTERS.limit().cellsPerColumn(5))
-            .filter(FILTERS.family().regex("a"))
-            .toProto(),
-        actualFilter.toProto());
+    assertThat(actualFilter.toProto())
+        .isEqualTo(
+            FILTERS
+                .chain()
+                .filter(FILTERS.limit().cellsPerColumn(5))
+                .filter(FILTERS.family().regex(".*a.*"))
+                .toProto());
   }
 }