diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index 303436c89d..0695e66399 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -21,7 +21,17 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ] <replaceable class="parameter">name</replaceable>
+REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ] <replaceable class="parameter">name</replaceable>
+
+<phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase>
+
+    FILTER = filter_option
+    VERBOSE
+
+<phrase>and <replaceable class="parameter">filter_option</replaceable> can only be:</phrase>
+
+    COLLATION
+
 </synopsis>
  </refsynopsisdiv>
 
@@ -165,6 +175,20 @@ REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURR
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><literal>FILTER</literal></term>
+    <listitem>
+     <para>
+      When a filter is used, <productname>PostgreSQL</productname> will only
+      rebuild a subset of indexes depending on the filters used.  For now, the
+      only available filter is <literal>COLLATION</literal>, which will
+      discard indexes whose ordering does not depend on a collation.  Note that
+      the FILTER option is not compatible with <command>REINDEX
+      SCHEMA</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><literal>VERBOSE</literal></term>
     <listitem>
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index bb60b23093..e0be50754b 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3524,7 +3524,7 @@ reindex_relation(Oid relid, int flags, int options)
 	 * relcache to get this with a sequential scan if ignoring system
 	 * indexes.)
 	 */
-	indexIds = RelationGetIndexList(rel);
+	indexIds = RelationGetIndexListFiltered(rel, options);
 
 	PG_TRY();
 	{
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 6fa5738bbf..4c3bb49230 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2790,7 +2790,7 @@ ReindexRelationConcurrently(Oid relationOid, int options)
 				heapRelation = table_open(relationOid, ShareUpdateExclusiveLock);
 
 				/* Add all the valid indexes of relation to list */
-				foreach(lc, RelationGetIndexList(heapRelation))
+				foreach(lc, RelationGetIndexListFiltered(heapRelation, options))
 				{
 					Oid			cellOid = lfirst_oid(lc);
 					Relation	indexRelation = index_open(cellOid,
@@ -2836,7 +2836,8 @@ ReindexRelationConcurrently(Oid relationOid, int options)
 
 					MemoryContextSwitchTo(oldcontext);
 
-					foreach(lc2, RelationGetIndexList(toastRelation))
+					foreach(lc2, RelationGetIndexListFiltered(toastRelation,
+															  options))
 					{
 						Oid			cellOid = lfirst_oid(lc2);
 						Relation	indexRelation = index_open(cellOid,
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 208b4a1f28..a1cb184ee2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -510,6 +510,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 %type <ival>	reindex_target_type reindex_target_multitable
 %type <ival>	reindex_option_list reindex_option_elem
+%type <ival>	reindex_filter reindex_filter_elem
 
 %type <node>	copy_generic_opt_arg copy_generic_opt_arg_list_item
 %type <defelt>	copy_generic_opt_elem
@@ -8387,7 +8388,14 @@ reindex_option_list:
 		;
 reindex_option_elem:
 			VERBOSE	{ $$ = REINDEXOPT_VERBOSE; }
+			| reindex_filter	{ $$ = $1; }
 		;
+reindex_filter:
+			FILTER '=' reindex_filter_elem { $$ = $3; }
+		;
+reindex_filter_elem:
+				COLLATION	{ $$ = REINDEXOPT_COLLATION; }
+				;
 
 /*****************************************************************************
  *
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 05ec7f3ac6..88cf88dff5 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -784,6 +784,9 @@ standard_ProcessUtility(PlannedStmt *pstmt,
 				switch (stmt->kind)
 				{
 					case REINDEX_OBJECT_INDEX:
+						if ((stmt->options & REINDEXOPT_ALL_FILTERS) != 0)
+							elog(ERROR, "FILTER clause is not compatible with REINDEX INDEX");
+
 						ReindexIndex(stmt->relation, stmt->options, stmt->concurrent);
 						break;
 					case REINDEX_OBJECT_TABLE:
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 2b992d7832..378592cf11 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -53,6 +53,7 @@
 #include "catalog/pg_database.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
+#include "catalog/pg_opfamily.h"
 #include "catalog/pg_partitioned_table.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_publication.h"
@@ -4433,6 +4434,96 @@ RelationGetIndexList(Relation relation)
 	return result;
 }
 
+/*
+ * RelationGetIndexListFiltered -- get a filtered list of indexes on this relation
+ *
+ * Calls RelationGetIndexList and filters out the result.
+ */
+List *
+RelationGetIndexListFiltered(Relation relation, int options)
+{
+	List	   *result,
+			   *full_list;
+	ListCell   *lc;
+
+	full_list = RelationGetIndexList(relation);
+
+	/* Quick exit if no filtering was asked of if the list is empty. */
+	if ((options & REINDEXOPT_ALL_FILTERS) == 0 || full_list == NIL)
+		return full_list;
+
+	result = NIL;
+	foreach(lc, full_list)
+	{
+		Oid			indexOid = lfirst_oid(lc);
+		Relation	index;
+		int			i,
+					numAtts;
+		bool		keepit = false;
+
+		index = index_open(indexOid, AccessShareLock);
+		numAtts = index->rd_index->indnatts;
+		index_close(index, AccessShareLock);
+
+		for (i = 0; i < numAtts; i++)
+		{
+			/*
+			 * If at least one column doesn't match the asked filter, we have
+			 * to keep the whole index.
+			 */
+			if (keepit)
+				break;
+
+			/*
+			 * The caller wants to discard indexes that doesn't depend on a
+			 * collation
+			 */
+			if (options & REINDEXOPT_COLLATION)
+			{
+				char		typcategory;
+				bool		typispreferred,
+							res;
+				Oid			opclass,
+							opfamily = InvalidOid,
+							opcintype = InvalidOid;
+
+				opclass = get_index_column_opclass(indexOid, i + 1);
+
+				res = get_opclass_opfamily_and_input_type(opclass, &opfamily,
+														  &opcintype);
+
+				if (!res)
+				{
+					keepit = true;
+					break;
+				}
+
+				/*
+				 * text_pattern_ops and varchar_pattern_ops doesn't depend on
+				 * a collation order.
+				 */
+				if (opfamily == TEXT_PATTERN_BTREE_FAM_OID ||
+					opfamily == BPCHAR_PATTERN_BTREE_FAM_OID)
+					continue;
+
+				get_type_category_preferred(opcintype, &typcategory,
+											&typispreferred);
+
+				if (typcategory == TYPCATEGORY_STRING)
+				{
+					keepit = true;
+					break;
+				}
+			}
+		}
+
+		if (keepit)
+			result = lappend_int(result, indexOid);
+	}
+
+	return result;
+}
+
 /*
  * RelationGetStatExtList
  *		get a list of OIDs of statistics objects on this relation
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 94ded3c135..a871bff556 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3301,6 +3301,10 @@ typedef struct ConstraintsSetStmt
 
 /* Reindex options */
 #define REINDEXOPT_VERBOSE 1 << 0	/* print progress info */
+#define REINDEXOPT_COLLATION 1 << 1	/* only reindex collation-dependent
+									 * indexes */
+
+#define REINDEXOPT_ALL_FILTERS (REINDEXOPT_COLLATION)
 
 typedef enum ReindexObjectType
 {
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index d9c10ffcba..c4ae25ef87 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -42,6 +42,7 @@ extern void RelationClose(Relation relation);
 /*
  * Routines to compute/retrieve additional cached information
  */
+extern List *RelationGetIndexListFiltered(Relation relation, int options);
 extern List *RelationGetFKeyList(Relation relation);
 extern List *RelationGetIndexList(Relation relation);
 extern List *RelationGetStatExtList(Relation relation);
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 9305649c11..4184c767db 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -1936,6 +1936,17 @@ CREATE TABLE reindex_verbose(id integer primary key);
 \set VERBOSITY terse \\ -- suppress machine-dependent details
 REINDEX (VERBOSE) TABLE reindex_verbose;
 INFO:  index "reindex_verbose_pkey" was reindexed
+REINDEX (VERBOSE, FILTER = COLLATION) TABLE reindex_verbose;
+NOTICE:  table "reindex_verbose" has no indexes to reindex
+-- One column, not depending on a collation
+CREATE INDEX ON reindex_verbose ((id)::text text_pattern_ops);
+ERROR:  syntax error at or near "::" at character 38
+-- Two columns, none depending on a collation
+CREATE INDEX ON reindex_verbose (id, (id::text) text_pattern_ops);
+-- Three columns, one depending on a collation
+CREATE INDEX ON reindex_verbose ((id::text), id, (id::text) text_pattern_ops);
+REINDEX (VERBOSE, FILTER = COLLATION) TABLE reindex_verbose;
+INFO:  index "reindex_verbose_id_id1_id2_idx" was reindexed
 \set VERBOSITY default
 DROP TABLE reindex_verbose;
 --
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index cd46f071bd..ee0336c9ca 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -744,6 +744,14 @@ explain (costs off)
 CREATE TABLE reindex_verbose(id integer primary key);
 \set VERBOSITY terse \\ -- suppress machine-dependent details
 REINDEX (VERBOSE) TABLE reindex_verbose;
+REINDEX (VERBOSE, FILTER = COLLATION) TABLE reindex_verbose;
+-- One column, not depending on a collation
+CREATE INDEX ON reindex_verbose ((id)::text text_pattern_ops);
+-- Two columns, none depending on a collation
+CREATE INDEX ON reindex_verbose (id, (id::text) text_pattern_ops);
+-- Three columns, one depending on a collation
+CREATE INDEX ON reindex_verbose ((id::text), id, (id::text) text_pattern_ops);
+REINDEX (VERBOSE, FILTER = COLLATION) TABLE reindex_verbose;
 \set VERBOSITY default
 DROP TABLE reindex_verbose;
 
