Listas do Redis (Parte 2)

Esta lição aborda operações avançadas de lista, incluindo consulta, modificação e inserção de elementos.

LINDEX: Obter Elemento por Índice

LINDEX recupera um elemento pelo seu índice sem removê-lo.

Uso Básico

REDIS
LPUSH mylist "um" "dois" "três" "quatro" "cinco"

# Obter o primeiro elemento (índice 0)
LINDEX mylist 0
"cinco"

# Obter o segundo elemento
LINDEX mylist 1
"quatro"

# Obter o último elemento
LINDEX mylist -1
"um"

# Obter o penúltimo elemento
LINDEX mylist -2
"dois"

Índice Fora do Intervalo

REDIS
# Retorna nil quando o índice está fora do intervalo
LINDEX mylist 10
(nil)

LINDEX mylist -10
(nil)
💡 Desempenho: LINDEX tem complexidade de tempo O(N), onde N é o valor absoluto do índice. Acesso à cabeça e cauda é rápido; acesso ao meio é lento.

LSET: Definir Elemento por Índice

LSET modifica o elemento em um índice especificado.

Uso Básico

REDIS
LRANGE mylist 0 -1
1) "cinco"
2) "quatro"
3) "três"
4) "dois"
5) "um"

# Modificar o primeiro elemento
LSET mylist 0 "PRIMEIRO"
OK

# Modificar o último elemento
LSET mylist -1 "ÚLTIMO"
OK

LRANGE mylist 0 -1
1) "PRIMEIRO"
2) "quatro"
3) "três"
4) "dois"
5) "ÚLTIMO"

Índice Fora do Intervalo

REDIS
LSET mylist 10 "valor"
(error) ERR index out of range
⚠️ Observação: LSET só pode modificar índices existentes — não pode inserir novos elementos.

LINSERT: Inserir Antes ou Depois de um Elemento de Referência

LINSERT insere um novo elemento antes ou depois de um elemento de referência especificado.

LINSERT BEFORE: Inserir Antes

REDIS
LRANGE mylist 0 -1
1) "PRIMEIRO"
2) "quatro"
3) "três"
4) "dois"
5) "ÚLTIMO"

# Inserir "ANTES_TRÊS" antes de "três"
LINSERT mylist BEFORE "três" "ANTES_TRÊS"
(integer) 6  # Retorna o tamanho da lista

LRANGE mylist 0 -1
1) "PRIMEIRO"
2) "quatro"
3) "ANTES_TRÊS"
4) "três"
5) "dois"
6) "ÚLTIMO"

LINSERT AFTER: Inserir Depois

REDIS
# Inserir "DEPOIS_TRÊS" depois de "três"
LINSERT mylist AFTER "três" "DEPOIS_TRÊS"
(integer) 7

LRANGE mylist 0 -1
1) "PRIMEIRO"
2) "quatro"
3) "ANTES_TRÊS"
4) "três"
5) "DEPOIS_TRÊS"
6) "dois"
7) "ÚLTIMO"

Elemento de Referência Não Encontrado

REDIS
# Elemento de referência especificado não existe
LINSERT mylist BEFORE "naoexiste" "valor"
(integer) -1  # Retorna -1 quando o pivô não é encontrado
⚠️ Aviso de desempenho: LINSERT tem complexidade de tempo O(N) — precisa percorrer a lista para encontrar o pivô. Isso é lento em listas muito longas.

LREM: Remover Elementos por Valor

LREM remove elementos da lista que correspondem a um valor especificado.

Uso Básico

REDIS
LPUSH mylist "a" "b" "a" "c" "a" "d"

LRANGE mylist 0 -1
1) "d"
2) "a"
3) "c"
4) "a"
5) "b"
6) "a"

# Remover 2 ocorrências de "a" a partir da cabeça
LREM mylist 2 "a"
(integer) 2  # Deletou 2

LRANGE mylist 0 -1
1) "d"
2) "c"
3) "b"
4) "a"

Referência de Parâmetros

Parâmetro Descrição
count > 0 Remover count ocorrências a partir da cabeça
count < 0 Remover abs(count) ocorrências a partir da cauda
count = 0 Remover todos os elementos correspondentes

Remover da Cauda

REDIS
LPUSH mylist "a" "b" "a" "c" "a"

# Remover 1 ocorrência de "a" a partir da cauda
LREM mylist -1 "a"
(integer) 1

Remover Todos os Elementos Correspondentes

REDIS
LPUSH mylist "a" "b" "a" "c" "a"

# Remover todos os "a"
LREM mylist 0 "a"
(integer) 3

LRANGE mylist 0 -1
1) "c"
2) "b"

RPOPLPUSH: Mover Elementos

RPOPLPUSH remove o elemento da cauda de uma lista e o insere na cabeça de outra lista.

Uso Básico

REDIS
# Lista de origem
LPUSH source "um" "dois" "três"

# Lista de destino
LPUSH destination "a" "b"

# Mover cauda da origem para cabeça do destino
RPOPLPUSH source destination
"um"  # Retorna o elemento movido

LRANGE source 0 -1
1) "três"
2) "dois"

LRANGE destination 0 -1
1) "um"
2) "a"
3) "b"

Caso de Uso: Fila Circular

REDIS
# Mover uma tarefa da cauda de volta para a cabeça para processamento round-robin
RPOPLPUSH queue:task queue:task

Caso de Uso: Fila de Backup

REDIS
# Mover tarefa para fila de backup durante o processamento
RPOPLPUSH queue:task queue:backup

# Se o processamento falhar, a tarefa pode ser recuperada da fila de backup

BRPOPLPUSH: Movimento Bloqueante

BRPOPLPUSH é a versão bloqueante de RPOPLPUSH.

REDIS
# Se a lista de origem estiver vazia, aguardar bloqueante por até 10 segundos
BRPOPLPUSH source destination 10
💡 Caso de uso: BRPOPLPUSH é comumente usado para filas de mensagens confiáveis para garantir que nenhuma mensagem seja perdida.

LMOVE: Mover Elementos (Redis 6.2+)

LMOVE é uma versão generalizada de RPOPLPUSH que permite especificar ambas as posições de origem e destino.

REDIS
# Remover da direita da origem, inserir à esquerda do destino
LMOVE source destination RIGHT LEFT

# Remover da esquerda da origem, inserir à direita do destino
LMOVE source destination LEFT RIGHT

Aplicações Avançadas de Lista

Caso de Uso 1: Paginação

REDIS
# Lista de artigos
LPUSH articles "article:1" "article:2" ... "article:100"

# Página 1 (10 itens por página)
LRANGE articles 0 9

# Página 2
LRANGE articles 10 19

# Página 3
LRANGE articles 20 29

Caso de Uso 2: Contatos Recentes

REDIS
# Adicionar um contato à lista recente
LPUSH contacts:user:1 "user:2"

# Se já existir, remover primeiro e depois adicionar (mover para o início)
LREM contacts:user:1 0 "user:2"
LPUSH contacts:user:1 "user:2"

# Obter 10 contatos recentes
LRANGE contacts:user:1 0 9

Caso de Uso 3: Escalonamento Round-Robin

REDIS
# Lista de tarefas
LPUSH tasks "task1" "task2" "task3"

# Round-robin: remover tarefa, processá-la, depois colocá-la de volta na cauda
RPOPLPUSH tasks tasks
"task1"  # Processar task1

# Próxima consulta obterá task2

Caso de Uso 4: Log Limitado

REDIS
# Adicionar uma entrada de log
LPUSH log:app "mensagem de log"

# Manter as 1000 entradas de log mais recentes
LTRIM log:app 0 999

# Visualizar logs recentes
LRANGE log:app 0 99

Otimização de Desempenho de Lista

1. Evitar Operações no Meio

REDIS
# ❌ Desempenho ruim: inserir ou deletar no meio
LINSERT mylist BEFORE "meio" "novo"
LREM mylist 1 "meio"

# ✅ Bom desempenho: operar apenas na cabeça e cauda
LPUSH mylist "novo"
LPOP mylist

2. Evitar Listas Grandes

REDIS
# ❌ Lista muito grande
LLEN mylist
(integer) 1000000

# ✅ Usar LTRIM para limitar o tamanho
LTRIM mylist 0 9999

3. Buscar em Lotes com LRANGE

REDIS
# ❌ Buscar um intervalo enorme de uma vez
LRANGE mylist 0 -1

# ✅ Buscar em lotes
LRANGE mylist 0 99
LRANGE mylist 100 199

4. Escolher a Estrutura de Dados Correta

Requisito Estrutura de Dados Recomendada
Fila/Pilha List
Últimos N itens List + LTRIM
Paginação List + LRANGE
Lista deduplicada Set ou Sorted Set
Ordenação ponderada Sorted Set

Limitações da Lista

1. Busca Lenta de Elementos

REDIS
# Encontrar um valor específico requer percorrer a lista inteira
LINDEX mylist 500000  # Operação O(N), muito lenta

2. Operações Lentas no Meio

REDIS
# Inserir ou deletar no meio requer deslocar elementos
LINSERT mylist BEFORE "meio" "novo"  # O(N)

3. Não Pode Encontrar Índice por Valor

Redis não fornece um comando para encontrar o índice de um valor pelo seu conteúdo. Isso deve ser implementado no nível da aplicação.

❓ Perguntas Frequentes

P Qual é a diferença entre LINDEX e LRANGE?
R LINDEX retorna um único elemento; LRANGE retorna uma lista de elementos. LINDEX mylist 0 é equivalente a LRANGE mylist 0 0.
P Como insiro um elemento no meio de uma lista?
R Use LINSERT, mas o desempenho é ruim. Se você precisar de inserções frequentes no meio, considere usar uma estrutura de dados diferente.
P RPOPLPUSH é atômico?
R Sim. RPOPLPUSH é atômico — ou é bem-sucedido completamente ou falha completamente.
P Como implemento uma fila de prioridade?
R Use múltiplas listas (ex.: queue:high, queue:low). Verifique filas de alta prioridade primeiro, depois as de baixa prioridade.
P Qual é a diferença entre list e set?
R Listas são ordenadas e permitem duplicatas; sets são não ordenados com elementos únicos. Use listas para ordem, sets para deduplicação.

📖 Resumo

📝 Atividades

  1. Operações de índice: Crie uma lista, use LINDEX para obter elementos em diferentes posições, use LSET para modificar elementos
  2. Inserir e deletar: Use LINSERT para inserir no meio, use LREM para remover elementos por valor
  3. Movimento de elementos: Use RPOPLPUSH para implementar uma fila circular para round-robin de tarefas
  4. Paginação: Crie uma lista com 20 elementos e implemente paginação com 5 itens por página

Próxima Lição

Na próxima lição, nós aprenderemos sobre Conjuntos do Redis (Parte 1), abordando operações básicas de conjunto.

100%