Pesquisa digitada sobre modelo complexo. Possível solução CQRS / NoSQL

5

Dado o seguinte modelo relacional:

Eu preciso implementar uma pesquisa digitada de hotéis, que deve ser capaz de consultar nome, cidade, país, categoria, tipo de hotel, preço de quarto, tipo personalizado, tipo de quarto personalizado ou qualquer combinação desses critérios.

No momento, estou fazendo isso com o Entity Framework, construindo dinamicamente uma consulta sobre a entidade-Hotel (IQueryable). Isso é bom, pois atualmente há muito poucos dados. No entanto, isso não é muito escalonável e, quando há muitos dados, isso fica muito lento, pois é uma consulta de 10 tabelas. Note que eu só preciso carregar os dados do hotel, não o gráfico inteiro.

Estou pensando em maneiras de melhorar a escalabilidade dessa parte. Eu tenho procurado soluções CQRS e talvez NoSQL.

Uma abordagem que eu tinha em mente é ter esse modelo no lado da escrita (para reforçar a consistência) e ter um modelo diferente no lado da leitura. Na gravação, eu atualizaria o modelo de leitura (viewmodel).

No entanto, como esse já é um modelo mais ou menos complexo em termos de relações, vejo alguns problemas com isso:

  • A atualização de metadados (como category, roomtype, hoteltype) exigiria que eu atualizasse todos os hotéis ou salas no modelo de leitura. Isso pode ser muito lento ou impossível, uma vez que há muitos dados.
  • Suponha que eu use um banco de dados de documentos como o MongoDB e salve um hotel com todos os itens relacionados desnormalizados; a consulta sobre essa tabela ainda não será lenta, pois ela precisa pesquisar dentro de cada documento ou ainda é bastante rápida. NoSQL?

Para resumir algumas perguntas:

  • Desnormalizar esse modelo é a abordagem correta e qual seria o melhor caminho?
  • O NoSQL será mais rápido?
  • Há alguma abordagem melhor que eu possa seguir ou maneiras de romper o relacionamento e nivelar a hierarquia enquanto ainda é capaz de fazer uma pesquisa digitada?
  • Idealmente, alguns campos também devem oferecer suporte à pesquisa difusa. Qual seria a melhor maneira de conseguir isso?
por Kenneth 15.12.2013 / 13:52
fonte

4 respostas

3

Em primeiro lugar, se esse for o esquema real, ele parece estar super normalizado.

  • Hotel_Category | Categorias
  • Hotel_HotelType | HotelTypes
  • Room_RoomType | RoomTypes
  • Hotel_Room | Quarto

são todos candidatos para serem unidos pelo emparelhamento. Então, em vez de 8 tabelas, você teria 4. O prefixo duplo em algumas de suas tabelas é uma dica de que a normalização foi levada longe demais.

A normalização prática ou pragmática é sempre um ato de equilíbrio. Nesse caso, acho que você foi longe demais na rota de normalização.

Em seguida, desempenho no lado do banco de dados relacional:

I need to implement a typed search for hotels, which should be able to query on name, city, country, category, hoteltype, roomprice, customtype, room custom type and roomtype or any combination of these criteria.

Desculpas se isso parece pedante, mas existem índices para todos esses elementos, certo? Se o sharding for o molho secreto da escala da web 1 , os índices serão um primeiro passo crítico para garantir que o seu banco de dados relacional possa ser dimensionado. 1 a partir de um vídeo viral parodiando certas razões na seleção do banco de dados. Basta google o termo, mas sei que é um vídeo NSFW.

Depois disso, precisamos analisar os modelos de gravação & leia modelos.

Com um esquema tão pequeno quanto esse, acho que essa abordagem é exagerada, especialmente se você não desnormalizar o esquema fornecido na pergunta. Tomar esse caminho é apenas adicionar gasolina a um fogo já quente - tudo o que você terá conseguido é diminuir o seu aplicativo mais rapidamente devido à complexidade.

Isso não quer dizer que as visualizações somente leitura não valeriam a pena considerar após reduzir o esquema. Pensando nas maneiras pelas quais as pessoas podem consultar salas, você pode criar visualizações por local + nome, local + preço, local + tipo, etc ...

O ideal é que você tenha métricas do uso existente para determinar quais visualizações você deve criar. Mas parece que você entende o domínio bem o suficiente para que você possa adivinhar com quais deles começar.

Finalmente, considere uma abordagem noSQL. E há uma razão pela qual eu levanto isso por último.

Se você não tentar nenhuma das opções acima, sua implementação noSQL terá um desempenho significativamente pior do que sua solução de banco de dados relacional existente. O maior desafio será o número de junções que você tem em suas consultas. Embora não seja provável que você tenha muitas junções complexas, os sistemas noSQL funcionam melhor com pouca ou nenhuma junção nas consultas.

Se você reduzir seu esquema como sugerido no primeiro segmento, poderá ter uma boa chance de migrar para o noSQL. Eu provavelmente colapsaria Hotel , Country , Room e Room_Type em uma tabela. Isso deixaria junções simples de lá contra Hotel_Category e Hotel_Type , mas suponho que essas duas tabelas sejam usadas com menos frequência ao encontrar salas.

Juntamente com o recolhimento do esquema, você precisará indexar os principais elementos com os quais deseja pesquisar. Talvez ainda mais do que os DBs relacionais, a abordagem noSQL depende muito do índice pré-construído para encontrar as informações de que você precisa rapidamente.

Notas de inicialização:

Na medida em que seria mais rápido (relacional versus noSQL), eu realmente não sei e eu não acho que ninguém poderia saber até que você tenha gasto algum tempo construindo e ajustando ambos. Trabalhar em um não se aplica ao outro, então você tem que dobrar seu esforço para realmente responder a essa parte da sua pergunta. Se você já investiu no lado relacional, não vejo nada de interessante em sua pergunta para mudar para o noSQL.

A pesquisa difusa pode ser um desafio, independentemente do tipo de banco de dados subjacente. A melhor coisa que você pode fazer aqui é examinar as opções fornecidas pela plataforma escolhida e começar a tentar implementar a pesquisa difusa. Perfil isso; continue revisando; e veja onde suas iterações levam você.

    
por 20.12.2013 / 20:30
fonte
1

Dê uma olhada no Solr . Ele pode fazer todas as coisas que você quer e muito mais, fora da caixa. Uma desvantagem possível é que você tem que empurrar seus dados para o servidor toda vez que tiver uma atualização (ou fazê-lo em lotes em intervalos específicos), mas como o Solr suporta importações delta, não deve ser uma grande complicação.

    
por 20.12.2013 / 16:44
fonte
1

Se suas consultas complexas são sempre baseadas em quartos de hotel, eu diria que você precisa escalar para desnormalizar (ou criar um índice).

Se você desnormalizar no SQL, eu optaria por uma abordagem OLAP . Uma simples tabela indexada e desnormalizada parece ser suficiente para escalar para milhões de linhas.

NoSQL (ou seja, MongoDB) também pode ser usado para isso. O princípio de design é semelhante a uma abordagem OLAP, mas apoiado por um banco de dados NoSQL.

Em qualquer caso, sugiro usar um back-end OLAP / desnormalizado somente para a parte de pesquisa indexada, mantendo a estrutura SQL para a parte de processamento transacional (exatamente como você mencionou, usando um "modelo de leitura") .

Você pode usar um mecanismo de busca como Solr (ou Lucene no seu caso) como sugerido, o que talvez possa ser visto como uma maneira de desnormalizar também. Eu não gosto dessa abordagem quando não preciso de pesquisa baseada em fuzzy / score / text. Dependendo do tipo de pesquisa difusa que você precisa, você pode evitar o Lucene e resolver a pesquisa difusa com um personalizado (ou seja, usando algoritmos de distância de seqüência de caracteres). Como um exemplo concreto: eu consideraria um mecanismo de busca como o Lucene se eu precisasse fazer uma pesquisa difusa baseada em "Cidade" ou outros campos de texto, mas talvez eu usasse algo personalizado baseado na "distância Levenshtein" se eu precisasse fazer pesquisas difusas simples em "País". Se você, no entanto, precisar de pesquisa baseada em pontuação (como: algum atributo de quarto não é realmente importante e não desqualificar a sala de estar listada), então vá com algum mecanismo de busca como o Lucene.

Finalmente, observe que ao consultar seu banco de dados o número de tabelas não é realmente uma grande preocupação, contanto que você esteja usando colunas indexadas para unir tabelas e sua cardinalidade não seja muito grande (ou seja, uma tabela "país" pode ser contida na memória e uni-lo em sua chave primária normalmente não afeta o desempenho). Essas junções são muito comuns em sistemas Relacionais-OLAP.

    
por 20.12.2013 / 17:13
fonte
-2

O que eu fiz para consultas complexas em grandes conjuntos de dados é o seguinte:

  • Execute uma consulta simples que inclua apenas uma ou duas tabelas
  • Truncar o número de resultados para um valor razoável (500k?)
  • Execute uma consulta mais complicada para restringir as opções com base nos registros truncados

Esta é uma solução escalável para o seu problema. Depois de começar a ingressar em muitas tabelas com milhões de registros, você multiplica o tamanho da tabela temporária usada na união. Ao truncar os resultados para uma quantidade gerenciável, as consultas ainda serão executadas rapidamente e, na maioria dos casos, você obterá 100% dos resultados. No caso em que seu truncamento remove hotéis válidos, você descobrirá que ainda obterá dezenas de milhares de resultados. É uma questão de ficar bem em não obter uma solução perfeitamente completa para obter resultados em tempo hábil.

No que diz respeito à pesquisa fuzzy, você pode estar falando sobre implementações da Web Semântica. Esta é uma tarefa difícil, mas seus resultados refinados podem ser superiores a outro site concorrente. Dê uma olhada no Portão para uma idéia (é Java). Essencialmente, gera anotações em blocos de texto que permitem realizar pesquisas de termos adicionais. Depois de adicionar stemming e uma ontologia abrangente ao seu anotador, ele se torna uma ferramenta de pesquisa muito poderosa.

Eu não tentei mudar para o NoSQL. Eu acho que os modelos relacionais têm mais ferramentas e mais desenvolvedores que estão confortáveis com eles. Achatar e distribuir dados nem sempre é a melhor escolha, mas se você tiver mais de 10 sistemas que podem participar de um modelo de dados distribuído, poderá encontrar as pesquisas mais rápidas. Isso é somente se você tiver os recursos para fazer isso acontecer. Certamente achatando o banco de dados com um único servidor, pois a fonte de dados seria um erro.

Espero que isso ajude!

    
por 20.12.2013 / 15:58
fonte