<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: How to create monotonic function to incrementally add obj_id for datasource in pyspark in Data Engineering</title>
    <link>https://community.databricks.com/t5/data-engineering/how-to-create-monotonic-function-to-incrementally-add-obj-id-for/m-p/168360#M55908</link>
    <description>&lt;P&gt;Why &lt;FONT face="courier new,courier"&gt;monotonically_increasing_id()&lt;/FONT&gt; Produces Non-Sequential IDs&lt;BR /&gt;That’s actually a super common trip-up! Spark does this by design to avoid an expensive global shuffle across nodes, but it definitely catches a lot of people off guard when they expect a simple 1, 2, 3 sequence.&lt;/P&gt;&lt;P&gt;&lt;FONT face="courier new,courier"&gt;monotonically_increasing_id()&lt;/FONT&gt; guarantees unique 64-bit integers that increase within each partition, but they are not consecutive across the whole DataFrame.&lt;/P&gt;&lt;P&gt;Because Spark is a distributed processing engine, each partition is assigned its own large block of IDs. The high 31 bits store the partition ID (calculated as &lt;FONT face="courier new,courier"&gt;partition_number × 2³³&lt;/FONT&gt;), while the low 33 bits store the record count within that specific partition. As a result, you see those huge numeric gaps between partitions (e.g., &lt;FONT face="courier new,courier"&gt;0, 1, 2,&lt;/FONT&gt; ... on Partition 0, then jumping to &lt;FONT face="courier new,courier"&gt;8589934592, 8589934593,&lt;/FONT&gt; ... on Partition 1).&lt;/P&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;STRONG&gt;Three Ways to Get Sequential IDs&lt;/STRONG&gt;&lt;BR /&gt;1. Use &lt;FONT face="courier new,courier"&gt;row_number()&lt;/FONT&gt; over &lt;FONT face="courier new,courier"&gt;monotonically_increasing_id()&lt;/FONT&gt; (recommended)&lt;BR /&gt;Combine both functions: first add the monotonic ID, then use &lt;FONT face="courier new,courier"&gt;row_number()&lt;/FONT&gt; with a window ordered by that ID to get clean 1, 2, 3, … values.&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;LI-CODE lang="python"&gt;from pyspark.sql.functions import monotonically_increasing_id, row_number, col
from pyspark.sql.window import Window

# Add monotonically increasing id first
df_with_mono_id = df.withColumn("mono_id", monotonically_increasing_id())

# Use row_number() over a window ordered by the monotonic id
window = Window.orderBy(col("mono_id"))
df_with_seq_id = df_with_mono_id.withColumn("row_id", row_number().over(window)).drop("mono_id")

df_with_seq_id.show()&lt;/LI-CODE&gt;&lt;LI-CODE lang="markup"&gt;Output:
+-----+---+------+
| Name|Age|row_id|
+-----+---+------+
|Alice| 10|     1|
|Susan| 12|     2|
+-----+---+------+&lt;/LI-CODE&gt;&lt;P&gt;Note: &lt;FONT face="courier new,courier"&gt;row_number()&lt;/FONT&gt; with a single partition window can be slow on very large datasets because all data is shuffled to one partition for ordering.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;2. Use &lt;FONT face="courier new,courier"&gt;zipWithIndex()&lt;/FONT&gt; via RDD (best for large datasets)&lt;/STRONG&gt;&lt;BR /&gt;This approach avoids the single-partition bottleneck by working at the RDD level:&lt;/P&gt;&lt;LI-CODE lang="python"&gt;from pyspark.sql.functions import col

# Convert to RDD, apply zipWithIndex, convert back
df_rdd = df.rdd.zipWithIndex().toDF()
df_with_id = df_rdd.select(col("_1.*"), col("_2").alias("row_id"))

df_with_id.show()&lt;/LI-CODE&gt;&lt;LI-CODE lang="markup"&gt;Output:
+-----+---+------+
| Name|Age|row_id|
+-----+---+------+
|Alice| 10|     0|
|Susan| 12|     1|
+-----+---+------+&lt;/LI-CODE&gt;&lt;P&gt;&lt;STRONG&gt;3. Start from a custom offset&lt;/STRONG&gt;&lt;BR /&gt;If you need IDs to continue from a previous maximum (e.g., for incremental loads):&lt;/P&gt;&lt;LI-CODE lang="python"&gt;from pyspark.sql.functions import monotonically_increasing_id, row_number, col, lit
from pyspark.sql.window import Window

previous_max_value = 1000  # fetch this from your existing table

df_with_mono_id = df.withColumn("mono_id", monotonically_increasing_id())
window = Window.orderBy(col("mono_id"))
df_final = (df_with_mono_id
    .withColumn("row_id", row_number().over(window) + lit(previous_max_value))
    .drop("mono_id"))

df_final.show()&lt;/LI-CODE&gt;&lt;LI-CODE lang="markup"&gt;Output:
+-----+---+------+
| Name|Age|row_id|
+-----+---+------+
|Alice| 10|  1001|
|Susan| 12|  1002|
+-----+---+------+&lt;/LI-CODE&gt;&lt;P&gt;&lt;STRONG&gt;Check the below details it will help you to decide which method to choose?&lt;/STRONG&gt;&lt;/P&gt;&lt;TABLE border="1" width="100%"&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD width="33.333333333333336%" height="30px"&gt;Method&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="30px"&gt;Pros&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="30px"&gt;Cons&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD width="33.333333333333336%" height="60px"&gt;&lt;FONT face="courier new,courier"&gt;row_number()&lt;/FONT&gt; over &lt;FONT face="courier new,courier"&gt;monotonically_increasing_id()&lt;/FONT&gt;&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="60px"&gt;Simple, stays in DataFrame API&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="60px"&gt;Single-partition shuffle; slow on very large data&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;&lt;FONT face="courier new,courier"&gt;zipWithIndex()&lt;/FONT&gt; via RDD&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;Distributed, efficient for large datasets&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;Requires RDD conversion and back&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;Custom offset&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;Supports incremental ID assignment&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;Same trade-offs as method 1&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;P&gt;For most use cases, &lt;STRONG&gt;method 1&lt;/STRONG&gt; &lt;FONT face="courier new,courier"&gt;(row_number())&lt;/FONT&gt; is the simplest. For very large datasets where performance matters, &lt;STRONG&gt;method 2&lt;/STRONG&gt; &lt;FONT face="courier new,courier"&gt;(zipWithIndex())&lt;/FONT&gt; is preferred.&lt;/P&gt;&lt;P&gt;Hope this should help!&lt;/P&gt;&lt;P&gt;Thanks!&lt;/P&gt;</description>
    <pubDate>Fri, 11 Sep 2026 12:17:29 GMT</pubDate>
    <dc:creator>osingh</dc:creator>
    <dc:date>2026-09-11T12:17:29Z</dc:date>
    <item>
      <title>How to create monotonic function to incrementally add obj_id for datasource in pyspark</title>
      <link>https://community.databricks.com/t5/data-engineering/how-to-create-monotonic-function-to-incrementally-add-obj-id-for/m-p/168343#M55901</link>
      <description>&lt;P&gt;I have used&amp;nbsp;monotonically_increasing_id() to add unique to datasource .However , this does not add unique id in increasing number ..Its kind of random.How to perform this in pyspark.&lt;/P&gt;</description>
      <pubDate>Fri, 11 Sep 2026 10:52:52 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/how-to-create-monotonic-function-to-incrementally-add-obj-id-for/m-p/168343#M55901</guid>
      <dc:creator>SandhyaDB</dc:creator>
      <dc:date>2026-09-11T10:52:52Z</dc:date>
    </item>
    <item>
      <title>Re: How to create monotonic function to incrementally add obj_id for datasource in pyspark</title>
      <link>https://community.databricks.com/t5/data-engineering/how-to-create-monotonic-function-to-incrementally-add-obj-id-for/m-p/168360#M55908</link>
      <description>&lt;P&gt;Why &lt;FONT face="courier new,courier"&gt;monotonically_increasing_id()&lt;/FONT&gt; Produces Non-Sequential IDs&lt;BR /&gt;That’s actually a super common trip-up! Spark does this by design to avoid an expensive global shuffle across nodes, but it definitely catches a lot of people off guard when they expect a simple 1, 2, 3 sequence.&lt;/P&gt;&lt;P&gt;&lt;FONT face="courier new,courier"&gt;monotonically_increasing_id()&lt;/FONT&gt; guarantees unique 64-bit integers that increase within each partition, but they are not consecutive across the whole DataFrame.&lt;/P&gt;&lt;P&gt;Because Spark is a distributed processing engine, each partition is assigned its own large block of IDs. The high 31 bits store the partition ID (calculated as &lt;FONT face="courier new,courier"&gt;partition_number × 2³³&lt;/FONT&gt;), while the low 33 bits store the record count within that specific partition. As a result, you see those huge numeric gaps between partitions (e.g., &lt;FONT face="courier new,courier"&gt;0, 1, 2,&lt;/FONT&gt; ... on Partition 0, then jumping to &lt;FONT face="courier new,courier"&gt;8589934592, 8589934593,&lt;/FONT&gt; ... on Partition 1).&lt;/P&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;STRONG&gt;Three Ways to Get Sequential IDs&lt;/STRONG&gt;&lt;BR /&gt;1. Use &lt;FONT face="courier new,courier"&gt;row_number()&lt;/FONT&gt; over &lt;FONT face="courier new,courier"&gt;monotonically_increasing_id()&lt;/FONT&gt; (recommended)&lt;BR /&gt;Combine both functions: first add the monotonic ID, then use &lt;FONT face="courier new,courier"&gt;row_number()&lt;/FONT&gt; with a window ordered by that ID to get clean 1, 2, 3, … values.&lt;/DIV&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;LI-CODE lang="python"&gt;from pyspark.sql.functions import monotonically_increasing_id, row_number, col
from pyspark.sql.window import Window

# Add monotonically increasing id first
df_with_mono_id = df.withColumn("mono_id", monotonically_increasing_id())

# Use row_number() over a window ordered by the monotonic id
window = Window.orderBy(col("mono_id"))
df_with_seq_id = df_with_mono_id.withColumn("row_id", row_number().over(window)).drop("mono_id")

df_with_seq_id.show()&lt;/LI-CODE&gt;&lt;LI-CODE lang="markup"&gt;Output:
+-----+---+------+
| Name|Age|row_id|
+-----+---+------+
|Alice| 10|     1|
|Susan| 12|     2|
+-----+---+------+&lt;/LI-CODE&gt;&lt;P&gt;Note: &lt;FONT face="courier new,courier"&gt;row_number()&lt;/FONT&gt; with a single partition window can be slow on very large datasets because all data is shuffled to one partition for ordering.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;2. Use &lt;FONT face="courier new,courier"&gt;zipWithIndex()&lt;/FONT&gt; via RDD (best for large datasets)&lt;/STRONG&gt;&lt;BR /&gt;This approach avoids the single-partition bottleneck by working at the RDD level:&lt;/P&gt;&lt;LI-CODE lang="python"&gt;from pyspark.sql.functions import col

# Convert to RDD, apply zipWithIndex, convert back
df_rdd = df.rdd.zipWithIndex().toDF()
df_with_id = df_rdd.select(col("_1.*"), col("_2").alias("row_id"))

df_with_id.show()&lt;/LI-CODE&gt;&lt;LI-CODE lang="markup"&gt;Output:
+-----+---+------+
| Name|Age|row_id|
+-----+---+------+
|Alice| 10|     0|
|Susan| 12|     1|
+-----+---+------+&lt;/LI-CODE&gt;&lt;P&gt;&lt;STRONG&gt;3. Start from a custom offset&lt;/STRONG&gt;&lt;BR /&gt;If you need IDs to continue from a previous maximum (e.g., for incremental loads):&lt;/P&gt;&lt;LI-CODE lang="python"&gt;from pyspark.sql.functions import monotonically_increasing_id, row_number, col, lit
from pyspark.sql.window import Window

previous_max_value = 1000  # fetch this from your existing table

df_with_mono_id = df.withColumn("mono_id", monotonically_increasing_id())
window = Window.orderBy(col("mono_id"))
df_final = (df_with_mono_id
    .withColumn("row_id", row_number().over(window) + lit(previous_max_value))
    .drop("mono_id"))

df_final.show()&lt;/LI-CODE&gt;&lt;LI-CODE lang="markup"&gt;Output:
+-----+---+------+
| Name|Age|row_id|
+-----+---+------+
|Alice| 10|  1001|
|Susan| 12|  1002|
+-----+---+------+&lt;/LI-CODE&gt;&lt;P&gt;&lt;STRONG&gt;Check the below details it will help you to decide which method to choose?&lt;/STRONG&gt;&lt;/P&gt;&lt;TABLE border="1" width="100%"&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD width="33.333333333333336%" height="30px"&gt;Method&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="30px"&gt;Pros&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="30px"&gt;Cons&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD width="33.333333333333336%" height="60px"&gt;&lt;FONT face="courier new,courier"&gt;row_number()&lt;/FONT&gt; over &lt;FONT face="courier new,courier"&gt;monotonically_increasing_id()&lt;/FONT&gt;&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="60px"&gt;Simple, stays in DataFrame API&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="60px"&gt;Single-partition shuffle; slow on very large data&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;&lt;FONT face="courier new,courier"&gt;zipWithIndex()&lt;/FONT&gt; via RDD&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;Distributed, efficient for large datasets&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;Requires RDD conversion and back&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;Custom offset&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;Supports incremental ID assignment&lt;/TD&gt;&lt;TD width="33.333333333333336%" height="57px"&gt;Same trade-offs as method 1&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;P&gt;For most use cases, &lt;STRONG&gt;method 1&lt;/STRONG&gt; &lt;FONT face="courier new,courier"&gt;(row_number())&lt;/FONT&gt; is the simplest. For very large datasets where performance matters, &lt;STRONG&gt;method 2&lt;/STRONG&gt; &lt;FONT face="courier new,courier"&gt;(zipWithIndex())&lt;/FONT&gt; is preferred.&lt;/P&gt;&lt;P&gt;Hope this should help!&lt;/P&gt;&lt;P&gt;Thanks!&lt;/P&gt;</description>
      <pubDate>Fri, 11 Sep 2026 12:17:29 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/how-to-create-monotonic-function-to-incrementally-add-obj-id-for/m-p/168360#M55908</guid>
      <dc:creator>osingh</dc:creator>
      <dc:date>2026-09-11T12:17:29Z</dc:date>
    </item>
    <item>
      <title>Re: How to create monotonic function to incrementally add obj_id for datasource in pyspark</title>
      <link>https://community.databricks.com/t5/data-engineering/how-to-create-monotonic-function-to-incrementally-add-obj-id-for/m-p/168368#M55910</link>
      <description>&lt;P&gt;Hey&amp;nbsp;&amp;nbsp;&lt;/P&gt;&lt;P&gt;So monotonically_increasing_id()&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;only promises the numbers go&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;up&amp;nbsp;and are&amp;nbsp;unique, not that they're neat like 1, 2, 3. Under the hood it bakes the partition number into the ID, so each partition jumps ahead by billions.&lt;/P&gt;&lt;P&gt;If you let me know what you're using the ID for and I'll point you to the cleanest option &lt;span class="lia-unicode-emoji" title=":slightly_smiling_face:"&gt;🙂&lt;/span&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 11 Sep 2026 13:31:01 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/how-to-create-monotonic-function-to-incrementally-add-obj-id-for/m-p/168368#M55910</guid>
      <dc:creator>DB-RKL</dc:creator>
      <dc:date>2026-09-11T13:31:01Z</dc:date>
    </item>
  </channel>
</rss>

