Full-Text Search in Android: Integrating FTS4 with Room

Cansu Cantürk
3 min readJul 28, 2024

--

What is FTS4?

FTS4 is a feature in SQLite that provides full-text search capabilities. It allows for rapid and efficient text searches, making it particularly useful for large text databases. FTS4 creates text indexes in SQLite and performs rapid searches through these indexes.

In traditional methods, full-text search is performed using the LIKE operator in SQL queries. This method can be slow and inefficient for large datasets.

SELECT * FROM notes WHERE content LIKE '%meeting%' AND content LIKE '%agenda%';

Disadvantages:

  • Performance: LIKE queries are slow on large datasets.
  • Exact Match Issues: Misspelled or incomplete words may not match.
  • Lack of Flexibility: Complex logical operations are limited.

Search with FTS4:

Example: To find notes containing “meeting” and “agenda”:

SELECT * FROM notes WHERE notes MATCH 'meeting AND agenda';

Advantages of using FTS4

  • Efficient Searches: FTS4 indexes text data, allowing for rapid searches across large datasets, significantly faster than traditional LIKE queries in SQL.
  • Complex Queries: It allows for complex queries using operators like AND and OR , enabling more specific searches.
  • Easy Integration: It can be easily integrated with SQLite and Room.
  • Handling Natural Language: FTS4 is equipped to handle natural language input, understands word stems and variations, resulting in more meaningful and accurate search results.

How to Use FTS4 with Room on Android?

Integrating FTS4 with Room in Android involves several steps to set up entities, DAOs, and databases properly.

1. Add Necessary Dependencies

Ensure your Android project includes the latest Room libraries, which support FTS4:

dependencies {
def room_version = "2.6.1" // Ensure this is the latest version

implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// For Kotlin projects, use kapt instead of annotationProcessor
kapt "androidx.room:room-compiler:$room_version"
}

2. Define the Entity

Define your entity class with the appropriate annotations for FTS4:

@Entity(tableName = "notes")
@Fts4
data class Note(
@PrimaryKey
@ColumnInfo(name = "rowid")
var id: Int = 0,
val content: String
)

3. Create the DAO

Create a DAO interface with methods for inserting notes and performing search queries:

@Dao
interface NoteDao {
@Insert
suspend fun insert(note: Note)

@Query("SELECT rowid, content FROM notes WHERE notes MATCH :query")
suspend fun search(query: String): List<Note>

@Query("DELETE FROM notes")
suspend fun deleteAll()
}

4. Set Up the Database

Set up the Room database to use the DAO and entity:

@Database(entities = [Note::class], version = 1)
abstract class NoteDatabase : RoomDatabase() {
abstract fun noteDao(): NoteDao

companion object {
@Volatile
private var INSTANCE: NoteDatabase? = null

fun getDatabase(context: Context): NoteDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
NoteDatabase::class.java,
"note_database"
).build()
INSTANCE = instance
instance
}
}
}
}

5. Performing Full-Text Search with FTS4

In your MainActivity, insert sample notes and perform search queries:

class MainActivity : ComponentActivity() {

private lateinit var db: NoteDatabase
private lateinit var noteDao: NoteDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

db = NoteDatabase.getDatabase(this)
noteDao = db.noteDao()

lifecycleScope.launch {
withContext(Dispatchers.IO) {
// Delete all notes
noteDao.deleteAll()

// Insert sample notes
noteDao.insert(Note(content = "This is a sample note about Compose"))
noteDao.insert(Note(content = "Room database is great for Android development"))
noteDao.insert(Note(content = "FTS4 allows fast full-text search"))
noteDao.insert(Note(content = "Kotlin is a modern programming language"))

// Perform AND search
val andQuery = "\"modern\" \"language\""
val andResults = noteDao.search(andQuery)
andResults.forEach { result ->
println("AND Search Result: ${result.content}")
}


// Perform OR search
val orQuery = "sample OR Kotlin"
val orResults = noteDao.search(orQuery)
orResults.forEach { result ->
println("OR Search Result: ${result.content}")
}
}
}
}
}

The output will be:

Conclusion

In summary, using FTS4 with Room in Android applications provides a highly efficient solution for implementing full-text search. Compared to traditional LIKE queries, FTS4 offers superior performance and advanced search features, such as ranking and tokenization. By integrating FTS4 with Room, developers can achieve faster and more accurate search results while maintaining the simplicity of Room’s abstraction layer. This combination enhances the overall user experience, making it an excellent choice for applications requiring robust and efficient text search capabilities.

--

--