Construindo um classificador de texto no Spark Shell do Mahout

Construindo um classificador de texto no Spark Shell do Mahout

Este tutorial o guiará pelas etapas usadas para treinar um modelo Naive Bayes Multinomial e criar um classificador de texto baseado nesse modelo usando o mahout spark-shell.

Pré-requisitos

Este tutorial pressupõe que você tenha suas variáveis ​​de ambiente do Spark configuradas para a mahout spark-shellvisualização: Reprodução com o Shell do Mahout . Além disso, assumimos que o Mahout está sendo executado no modo de cluster (ou seja, com a MAHOUT_LOCALvariável de ambiente não definida ), conforme estaremos lendo e gravando no HDFS.

Download e vetorização do conjunto de dados da Wikipedia

A partir de Mahout v. 0.10.0, ainda estamos dependentes das versões MapReduce de mahout seqwikimahout seq2sparsepara extrair e vetorizar nosso texto. Uma implementação Spark do seq2sparse está em andamento para o Mahout v. 0.11. No entanto, para baixar o conjunto de dados da Wikipedia, extrair os corpos da documentação, rotular cada documento e vetorizar o texto em vetores TF-IDF, podemos executar o exemplo de wikipedia-classifier.sh de forma simples .

Please select a number to choose the corresponding task to run
1. CBayes (may require increased heap space on yarn)
2. BinaryCBayes
3. clean -- cleans up the work area in /tmp/mahout-work-wiki
Enter your choice :

Digite (2). Isso fará o download de um grande dump XML recente do banco de dados da Wikipedia, em um /tmp/mahout-work-wikidiretório, descompactá-lo e colocá-lo no HDFS. Ele executará um trabalho MapReduce para analisar o conjunto da wikipedia , extraindo e rotulando apenas páginas com tags de categoria para [Estados Unidos] e [Reino Unido] (documentos ~ 11600). Em seguida, ele será executado mahout seq2sparsepara converter os documentos em vetores TF-IDF. O script também irá compilar e testar um modelo Naive Bayes usando o MapReduce . Quando estiver concluído, você verá uma matriz de confusão na tela. Para este tutorial, vamos ignorar o modelo MapReduce e construir um novo modelo usando o Spark baseado na saída de texto vetorizado por seq2sparse.

Começando

Inicie o mahout spark-shell. Há um script de exemplo: spark-document-classifier.mscala(.mscala denota um script Mahout-Scala que pode ser executado de forma semelhante a um script R). Nós estaremos percorrendo este script para este tutorial, mas se você quisesse simplesmente executar o script, você poderia simplesmente emitir o comando:

mahout> :load /path/to/mahout/examples/bin/spark-document-classifier.mscala

Por enquanto, vamos desmontar o roteiro, peça por peça. Você pode recortar e colar os seguintes blocos de código no mahout spark-shell.

Importações

Nossas importações de Mahout Naive Bayes:

import org.apache.mahout.classifier.naivebayes._
import org.apache.mahout.classifier.stats._
import org.apache.mahout.nlp.tfidf._

Importações Hadoop necessárias para ler o nosso dicionário:

import org.apache.hadoop.io.Text
import org.apache.hadoop.io.IntWritable
import org.apache.hadoop.io.LongWritable

Leia em nosso conjunto completo do HDFS como vetorizado por seq2sparse em classify-wikipedia.sh

val pathToData = "/tmp/mahout-work-wiki/"
val fullData = drmDfsRead(pathToData + "wikipediaVecs/tfidf-vectors")

Extrair a categoria de cada observação e agregar essas observações por categoria

val (labelIndex, aggregatedObservations) = SparkNaiveBayes.extractLabelsAndAggregateObservations(
                                                             fullData)

Construa um modelo Muitinomial Naive Bayes e autoteste no conjunto de treinamento

val model = SparkNaiveBayes.train(aggregatedObservations, labelIndex, false)
val resAnalyzer = SparkNaiveBayes.test(model, fullData, false)
println(resAnalyzer)

imprimir o ResultAnalyzermostrará a matriz de confusão.

Leia no dicionário e conte a frequência de documentos do HDFS

val dictionary = sdc.sequenceFile(pathToData + "wikipediaVecs/dictionary.file-0",
                                  classOf[Text],
                                  classOf[IntWritable])
val documentFrequencyCount = sdc.sequenceFile(pathToData + "wikipediaVecs/df-count",
                                              classOf[IntWritable],
                                              classOf[LongWritable])

// setup the dictionary and document frequency count as maps
val dictionaryRDD = dictionary.map { 
                                case (wKey, wVal) => wKey.asInstanceOf[Text]
                                                         .toString() -> wVal.get() 
                                   }
                                   
val documentFrequencyCountRDD = documentFrequencyCount.map {
                                        case (wKey, wVal) => wKey.asInstanceOf[IntWritable]
                                                                 .get() -> wVal.get() 
                                                           }

val dictionaryMap = dictionaryRDD.collect.map(x => x._1.toString -> x._2.toInt).toMap
val dfCountMap = documentFrequencyCountRDD.collect.map(x => x._1.toInt -> x._2.toLong).toMap

Definir uma função para tokenize e vectorize o novo texto usando nosso dicionário atual

Para este exemplo simples, nossa função vectorizeDocument(...)irá converter um novo documento em unigramas usando métodos nativos de String Java e vetorizar usando nossas frequências de dicionário e documento. Você também pode usar um analisador Lucene para bigramas, trigramas, etc. e integrar o Apache Tika para extrair texto de diferentes tipos de documentos (PDF, PPT, XLS, etc.). Aqui, no entanto, vamos mantê-lo simples, separando e tokenizing nosso texto usando regexs e métodos nativos de String.

def vectorizeDocument(document: String,
                        dictionaryMap: Map[String,Int],
                        dfMap: Map[Int,Long]): Vector = {
    val wordCounts = document.replaceAll("[^\\p{L}\\p{Nd}]+", " ")
                                .toLowerCase
                                .split(" ")
                                .groupBy(identity)
                                .mapValues(_.length)         
    val vec = new RandomAccessSparseVector(dictionaryMap.size)
    val totalDFSize = dfMap(-1)
    val docSize = wordCounts.size
    for (word <- wordCounts) {
        val term = word._1
        if (dictionaryMap.contains(term)) {
            val tfidf: TermWeight = new TFIDF()
            val termFreq = word._2
            val dictIndex = dictionaryMap(term)
            val docFreq = dfCountMap(dictIndex)
            val currentTfIdf = tfidf.calculate(termFreq,
                                               docFreq.toInt,
                                               docSize,
                                               totalDFSize.toInt)
            vec.setQuick(dictIndex, currentTfIdf)
        }
    }
    vec
}

Configure nosso classificador

val labelMap = model.labelIndex
val numLabels = model.numLabels
val reverseLabelMap = labelMap.map(x => x._2 -> x._1)

// instantiate the correct type of classifier
val classifier = model.isComplementary match {
    case true => new ComplementaryNBClassifier(model)
    case _ => new StandardNBClassifier(model)
}

Definir uma função argmax

O rótulo com a pontuação mais alta ganha a classificação de um determinado documento.

def argmax(v: Vector): (Int, Double) = {
    var bestIdx: Int = Integer.MIN_VALUE
    var bestScore: Double = Integer.MIN_VALUE.asInstanceOf[Int].toDouble
    for(i <- 0 until v.size) {
        if(v(i) > bestScore){
            bestScore = v(i)
            bestIdx = i
        }
    }
    (bestIdx, bestScore)
}

Defina nosso classificador de vetores TF (-IDF)

def classifyDocument(clvec: Vector) : String = {
    val cvec = classifier.classifyFull(clvec)
    val (bestIdx, bestScore) = argmax(cvec)
    reverseLabelMap(bestIdx)
}

Dois exemplos de artigos de notícias: Futebol dos Estados Unidos e Futebol do Reino Unido

// A random United States football article
// http://www.reuters.com/article/2015/01/28/us-nfl-superbowl-security-idUSKBN0L12JR20150128
val UStextToClassify = new String("(Reuters) - Super Bowl security officials acknowledge" +
    " the NFL championship game represents a high profile target on a world stage but are" +
    " unaware of any specific credible threats against Sunday's showcase. In advance of" +
    " one of the world's biggest single day sporting events, Homeland Security Secretary" +
    " Jeh Johnson was in Glendale on Wednesday to review security preparations and tour" +
    " University of Phoenix Stadium where the Seattle Seahawks and New England Patriots" +
    " will battle. Deadly shootings in Paris and arrest of suspects in Belgium, Greece and" +
    " Germany heightened fears of more attacks around the world and social media accounts" +
    " linked to Middle East militant groups have carried a number of threats to attack" +
    " high-profile U.S. events. There is no specific credible threat, said Johnson, who" + 
    " has appointed a federal coordination team to work with local, state and federal" +
    " agencies to ensure safety of fans, players and other workers associated with the" + 
    " Super Bowl. I'm confident we will have a safe and secure and successful event." +
    " Sunday's game has been given a Special Event Assessment Rating (SEAR) 1 rating, the" +
    " same as in previous years, except for the year after the Sept. 11, 2001 attacks, when" +
    " a higher level was declared. But security will be tight and visible around Super" +
    " Bowl-related events as well as during the game itself. All fans will pass through" +
    " metal detectors and pat downs. Over 4,000 private security personnel will be deployed" +
    " and the almost 3,000 member Phoenix police force will be on Super Bowl duty. Nuclear" +
    " device sniffing teams will be deployed and a network of Bio-Watch detectors will be" +
    " set up to provide a warning in the event of a biological attack. The Department of" +
    " Homeland Security (DHS) said in a press release it had held special cyber-security" +
    " and anti-sniper training sessions. A U.S. official said the Transportation Security" +
    " Administration, which is responsible for screening airline passengers, will add" +
    " screeners and checkpoint lanes at airports. Federal air marshals, behavior detection" +
    " officers and dog teams will help to secure transportation systems in the area. We" +
    " will be ramping it (security) up on Sunday, there is no doubt about that, said Federal"+
    " Coordinator Matthew Allen, the DHS point of contact for planning and support. I have" +
    " every confidence the public safety agencies that represented in the planning process" +
    " are going to have their best and brightest out there this weekend and we will have" +
    " a very safe Super Bowl.")

// A random United Kingdom football article
// http://www.reuters.com/article/2015/01/26/manchester-united-swissquote-idUSL6N0V52RZ20150126
val UKtextToClassify = new String("(Reuters) - Manchester United have signed a sponsorship" +
    " deal with online financial trading company Swissquote, expanding the commercial" +
    " partnerships that have helped to make the English club one of the richest teams in" +
    " world soccer. United did not give a value for the deal, the club's first in the sector," +
    " but said on Monday it was a multi-year agreement. The Premier League club, 20 times" +
    " English champions, claim to have 659 million followers around the globe, making the" +
    " United name attractive to major brands like Chevrolet cars and sportswear group Adidas." +
    " Swissquote said the global deal would allow it to use United's popularity in Asia to" +
    " help it meet its targets for expansion in China. Among benefits from the deal," +
    " Swissquote's clients will have a chance to meet United players and get behind the scenes" +
    " at the Old Trafford stadium. Swissquote is a Geneva-based online trading company that" +
    " allows retail investors to buy and sell foreign exchange, equities, bonds and other asset" +
    " classes. Like other retail FX brokers, Swissquote was left nursing losses on the Swiss" +
    " franc after Switzerland's central bank stunned markets this month by abandoning its cap" +
    " on the currency. The fallout from the abrupt move put rival and West Ham United shirt" +
    " sponsor Alpari UK into administration. Swissquote itself was forced to book a 25 million" +
    " Swiss francs ($28 million) provision for its clients who were left out of pocket" +
    " following the franc's surge. United's ability to grow revenues off the pitch has made" +
    " them the second richest club in the world behind Spain's Real Madrid, despite a" +
    " downturn in their playing fortunes. United Managing Director Richard Arnold said" +
    " there was still lots of scope for United to develop sponsorships in other areas of" +
    " business. The last quoted statistics that we had showed that of the top 25 sponsorship" +
    " categories, we were only active in 15 of those, Arnold told Reuters. I think there is a" +
    " huge potential still for the club, and the other thing we have seen is there is very" +
    " significant growth even within categories. United have endured a tricky transition" +
    " following the retirement of manager Alex Ferguson in 2013, finishing seventh in the" +
    " Premier League last season and missing out on a place in the lucrative Champions League." +
    " ($1 = 0.8910 Swiss francs) (Writing by Neil Maidment, additional reporting by Jemima" + 
    " Kelly; editing by Keith Weir)")

Vetorize e classifique nossos documentos

val usVec = vectorizeDocument(UStextToClassify, dictionaryMap, dfCountMap)
val ukVec = vectorizeDocument(UKtextToClassify, dictionaryMap, dfCountMap)

println("Classifying the news article about superbowl security (united states)")
classifyDocument(usVec)

println("Classifying the news article about Manchester United (united kingdom)")
classifyDocument(ukVec)

Amarre tudo em um novo método para classificar o texto

def classifyText(txt: String): String = {
    val v = vectorizeDocument(txt, dictionaryMap, dfCountMap)
    classifyDocument(v)
}

Agora podemos simplesmente chamar nosso método classifyText (…) em qualquer String

classifyText("Hello world from Queens")
classifyText("Hello world from London")

Persistência do modelo

Você pode salvar o modelo no HDFS:

model.dfsWrite("/path/to/model")

E recupere-o com:

val model =  NBModel.dfsRead("/path/to/model")

O modelo treinado agora pode ser incorporado em um aplicativo externo.

 

Fonte:  http://mahout.apache.org/docs/latest/tutorials/samsara/classify-a-doc-from-the-shell.html

Apache – Proxy Reverso

Como montar um proxy reverse no servidor Apache

O que vem a ser um proxy reverse

O que vem a ser necessariamente um Proxy Reverse?

Imagine que você tenha uma máquina Linux rodando o Apache como servidor de aplicações web com páginas em HTML que pode ser facilmente acessado por qualquer pessoa de qualquer lugar.

Bom, suponhamos que você tem dois servidores Windows 2000 Server rodando na rede interna com IPs não roteáveis, um rodando aplicações ASP com o Serviço IIS (Internet Information Service) e outro rodando aplicações Java, por exemplo o JakartaTomCat. Ambos acessando um bando de dados robusto do tipo Oracle ou outro banco qualquer.

Só que essas máquinas só conseguem responder por http://192.168.0.1/aplicacao ou http://servidor_windows/aplicacao, ou seja, somente as máquinas da sua rede interna poderão navegar na aplicação e você não tem nenhum ip verdadeiro para estar delegando a essas máquinas para poder torná-las acessíveis para a internet.

Aí entra a jogada o Proxy Reverse! O Proxy Reverse pode ser entendido também como Cluster Web, ou seja, uma máquina principal recebe a solicitação e essa máquina tem por objetivo solicitar o serviço de outra máquina. Não entenda como redirecionamento e sim como troca de processamento, sendo que o processamento estará sendo dividido, ou seja, uma estará postando as informações e a outra estará fornecendo o serviço.

Configurando o Apache para o funcionamento do proxy

Passei um bom tempo estudando o funcionamento desse serviço de Proxy Reverse, pois eu não conhecia ninguém que já tivesse feito isso, porém tive o auxílio de um grande amigo e professor chamado Ulisses T.V. Guedes (responsável pela área de redes do Instituto Nacional de Pesquisa Espaciais) e aqui deixo meus votos de agradecimentos à ele.

No meu caso utilizei o Apache 1.3.27 instalado num Slackware 8.1. As aplicações envolvidas são:

  • Windows 2000 Server rodando o IIS com páginas ASP;
  • Windows 2000 Server rodando o Jakarta TomCat da Apache.

Suponhamos que esses 2 Servidores Windows já estão configurados para rodar, só que com IPs não roteáveis, ou seja, somente na rede interna.

No caso, somente o Apache que está rodando no Slackware tem o domínio válido e pode ser acessado. Chamaremos o domínio de http://www.empresa.com.brpara o exemplo.

Como sou do tipo que gosto de fazer tudo na unha, tive que baixar o pacote .tar.gz do Apache, descompactar e compilar. Vamos a receita do bolo!

Os seguintes pacotes foram utilizados:

  • apache_1.3.27.tar.gz
  • mod_ssl-2.8.14-1.3.27.tar.gz
  • php-4.3.4RC2.tar.gz
  • openssl-0.9.6i.tar.gz

Vou ser bonzinho e explicar todos os passos desde a instalação do Apache completo até…. 😉

NOTA: vou partir do princípio que você já fez o download dos pacotes, que podem ser facilmente encontrados a partir do site de buscahttp://freshmeat.net.

Primeiro passo, descompacte todos os pacotes num diretório qualquer. No meu caso, escolhi /usr/local/src e lá coloquei os arquivos:

# cd /usr/local/src
# tar -zxvf apache_1.3.27.tar.gz
# tar -zxvf mod_ssl-2.8.14-1.3.27.tar.gz
# tar -zxvf php-4.3.4RC2.tar.gz
# tar -zxvf openssl-0.9.6i.tar.gz

Comece a instalação pelo PHP:

# cd php-4.3.RC2
# ./configure –with-apache=../apache_1.3.27
# make
# make install

Agora vá para o diretório do OpenSSL:

# cd ../Openssl-0.9.6i
# ./config
# make
# make install

Agora o ModSSL:

# cd ../mod_ssl-2.8.14-1.3.27
# ./configure –with-apache=../apache_1.3.27 –with-ssl=../openssl-0.9.6i

Agora o Apache:

# ./configure –with-prefix=/usr/local/apache –with-bindir=/usr/local/bin –with-sbindir=/usr/local/sbin –enable-module=ssl –enable-module=proxy –enable-shared=proxy –enable-module-rewrite –enable-shared=rewrite –activate-module=src/modules/libphp4.a
# make
# make certificate
# make install

Falei que gosto de fazer as coisas na mão né? rs. Taí o resultado, porém funciona somente com os módulos que quero.

O importante são os parâmetros –enable-module=proxy e –enable-module=rewrite. No caso de instalações por RPM tipo RedHat, esses módulos vem ativados por padrão, bastando apenas desativar na configuração do httpd.conf o que você não deseja carregar.

Para finalizar a configuração do Apache, volte para o diretório do PHP e copie o arquivo php.ini-dist para /usr/local/lib/php.ini.

Configurando o proxy reverse para acessar outras máquinas

Após tudo estar funcionando, vá para o diretório do Apache e edite o arquivo de configurações:

# cd /usr/local/apache/conf
# vi httpd.conf

Nele, verifique se as seguintes configurações foram bem sucedidas na instalação:

LoadModule rewrite_module     libexec/mod_rewrite.so
LoadModule php4_module        libexec/libphp4.so  -> esse é apenas para o PHP
LoadModule proxy_module       libexec/libproxy.so

AddModule mod_proxy.c
AddModule mod_rewrite.c

Esses caras são os responsáveis pelo funcionamento do Proxy Reverse. Caso esses não estejam declarados, reveja a compilação do seu Apache.

Agora vamos para o que interessa realmente, procure a linha <IfModule mod_proxy.c>, iremos trabalhar com ela agora:

<IfModule mod_proxy.c>
ProxyRequests Off   -> deixe essa linha como Off, já tive problema com ela
ProxyPass /serv1/ http://192.168.0.22:80/serv1/
ProxyPassReverse /serv1/ http://192.168.0.22:80/serv1/
<Directory /usr/local/apache/htdocs/serv1>
Order Allow,deny
Allow from all
</Directory>
Redirect Permanent /serv1 https://www.empresa.com.br/serv1/
Nessa primeira passagem está acontecendo o seguinte:

O que se refere a ProxyPass /serv1, significa que quando alguém digitar http://www.empresa.com.br/serv1 ele irá solicitar o serviço emhttp://192.168.0.22:80/serv1/ ou seja, o serviço solicitado roda na porta 80 do primeiro servidor na rede interna.

Um detalhe importante é que a primeira solicitação que é o serv1 digitado no http://www.empresa.com.br tem que ser idêntica a entrada do servidor da rede interna, ou seja, no primeiro caso é um IIS que está rodando no 192.168.0.22, então no diretório de serviços dele a pasta onde se encontra as páginas ASP tem que se chamar serv1 (nesse exemplo é claro).

Uma vez encontrado, o ProxyPassReverse devolve a solicitação e quem vai postar a tela é o Apache, sendo que ele não precisa ter suporte a ASP, pois quem está processando páginas ASP é o Windows 2000. Isso forma um cluster, as duas máquinas estão processando as informações e deixando o serviço bem mais rápido.

A diretiva <Directory /usr/local/apache/htdocs/serv1> tem que existir, pois o Apache está fazendo de conta que é ele quem é dono do serviço. então você tem que ter criada uma pasta chamada serv1 no seu htdocs do Apache.

No Redirect Permanent estou forçando para que a navegação do servidor Windows 2000 Server utilize a criptografia de SSL criada no Apache, ou seja oWindows 2000 não tem criptografia, então o Apache fornece o serviço de criptografia.

Continuando dentro da tag <IfModule mod_proxy.c>, vamos ao exemplo de configuração para o segundo servidor:

    ProxyPass /clijava/ http://192.168.0.20/clijava/
ProxyPassReverse /clijava/ http://192.168.0.20/clijava/
AllowCONNECT 443
<Directory /usr/local/apache/htdocs/clijava>
Order Allow,deny
Allow from all
</Directory>
Redirect Permanent /clijava https://www.empresa.com.br/clijava/
</IfModule>
Essa outra diretiva está acionando o outro Windows 20000, o que roda o Jakarta TomCat. O procedimento é quase idêntico ao que expliquei acima, sendo que nesse caso o AllowCONNECT 443 é utilizado porque além da criptografia do Apache, o Jakarta também está criptografado, então nesse caso os dois servidores estão conversando em criptografia.

Em todo o caso o Jakarta não precisaria estar criptografado, mas fiz uns testes com ele e percebi que se os dois estiverem criptografado, tenho que usar essa diretiva.

E por fim:

ProxyVia On

<IfModule mod_disk_cache.c>
CacheRoot “/usr/local/apache/proxy”
CacheSize 5
CacheGcInterval 4
CacheMaxExpire 24
CacheLastModifiedFactor 0.1
CacheDefaultExpire 1
</IfModule>

Isso serve para a troca de cache e é extremamente importante, dependendo de quantas requisições seu servidor interno tiver, você tem que alterar esse números ai. Caso queira saber mais a fundo consulte a documentação do Apache.

Finalmente, pronto!

Aqui termino minha publicação do artigo e espero que isso possa ajudar alguém como tem me ajudado até hoje. Caso alguém tenha alguma dúvida, estarei a disposição para poder exclarecê-las.

 

Fonte:  http://xoops.net.br/docs/apache/apache-proxy-reverso/index.php

httpd.conf

O httpd.conf é o arquivo principal de configuração do Apache, que se encontra dentro da pasta Conf, no diretório de instalação do Apache.

O arquivo está dividido em três seções, que são:

1  Parâmetros globais
2 Diretivas de Funcionamento
3 Host Virtuais

No arquivo encontram-se todos os parâmetros de funcionamento do Apache. Alguns parâmetros são gerais para a instalação e funcionamento do Apache. Muitos dos outros parâmetros pode configurar independentes para um conjunto de diretórios e/ou arquivos. Nestes casos, os parâmetros se encontram localizados dentro de seções onde se indica o âmbito de aplicação do parâmetro.

As seções mais importantes são:

<Directory> : Os parâmetros que se encontram dentro desta seção, só se aplicarão ao diretório especificado e a seus subdiretórios.

<DirectoryMatch>: Igual ao Directory, porém aceita no nome do diretório expressões regulares.

<Files>: Os parâmetros de configuração proporcionam controle de acesso dos arquivos pelo seu nome.

<FilesMatch>: Igual ao Files, porém aceita expressões regulares no nome do arquivo.

<Location>: Proporciona um controle de acesso dos arquivos por meio da URL

<LocationMatch>: Igual ao Location, porém aceita expressões regulares no nomes do arquivo.

Algumas vezes as diretivas de funcionamento das seções anteriores se podem cruzar em cujo caso tenha a seguinte ordem de preferência:

1. <Directory> e .htaccess (.htaccess prevalece frente a <Directory>)
2. <DirectoryMatch> e <Directory>
3. <Files> e <FilesMatch>
4. <Location> e <LocationMatch>

Também há que destacar, que o arquivo contém vários comentários para sua correta utilização, as linhas comentadas aparecem com o símbolo #.

Onde encontro o arquivo httpd.conf do Apache?

Se você é usuário do Linux e o Apache 2 foi instalado no local padrão, então o arquivo poderá ser encontrado na pasta /etc/apache2/

Porém, as configurações principais do servidor Apache2 devem ser feitas no arquivo apache2.conf, que se encontra no mesmo diretório citado no parágrafo anterior.

Caso você esteja procurando o local onde se configura os domínios para a criação de múltiplos sites em um mesmo servidor (Virtual Host) o arquivo onde se encontram estas configurações é o /etc/apache2/sites-available/default