Jump to content

[JAVA] [TP] Recherche dans un index


Recommended Posts

Bonjour,

Pourriez-vous s'il vous plait m'aider pour coder les méthodes de ces différentes interfaces

En vous remerciant par avance

La ligne de commande permet d'effectuer des requêtes sur un index

java -jar exo.jar query [-n count] fichier.ext.idx expr

effectue une requête expr sur l'index fichier.ext.idx et affiche l'ensemble des lignes satisfaisant la requête.

-n permet de spécifier le nombre de résultat voulu.

Les requêtes sur l'index correspond à un arbre au format préfixé,

exemple "& toto | titi @t?t?" est équivalent à l'arbre

	  &
toto			| 
	titi		   @t?t?

L'opérateur ET ('&') reporte la ligne uniquement si les deux mots appartiennent à la ligne.

L'opérateur OU ('|') reporte la ligne si un des deux mots appartient à la ligne.

L'opérateur @ permet d'indiquer une expression régulière (au format PERL) pour rechercher les mots.

Lors de requête concernant beaucoup de résultat possible, il est possible de manipuler des itérateurs plutôt que des listes pour éviter d'avoir de grosses structures de données intermédiaires.

Les quelques interfaces à implémenter

import java.util.Collection;
public interface ContextStrategy {
 public Collection<? extends CharSequence> getContext(Result result);
}

--------------------------------------------------------------------------

import java.io.File;
import java.io.IOException;
import java.io.Reader;

import java.util.Map;
import java.util.regex.Pattern;


public interface FoogleFacade {
 public Index loadIndex(File indexFile)  throws IOException;

 public QueryFactory createQueryFactory(Index index);
}


public interface Index {
 public String getFilename();

 public ContextStrategy getContextStrategy();
}


public interface Query {
 public Iterable<? extends Result> execute();

 public Iterable<? extends Result> execute(int maxCount);
}

--------------------------------------------------------------------------

import java.util.regex.Pattern;

public interface QueryFactory {

 public Query query(CharSequence word);

 public Query query(Pattern pattern);

 public Query or(Query query1,Query query2);

 public Query and(Query query1,Query query2);
}


public interface Result {
 public int getLine();
}

pour pouvoir avoir comme main ceci:

FoogleFacade foogle = new FoogleFacadeImpl();

Index index=foogle.loadIndex(new File("bbe.idx"));
System.out.println("indexed filename:"+index.getFilename());

QueryFactory factory=foogle.createQueryFactory(index);
Query query=factory.and(factory2.query("God"),
factory.query("solid"));

ContextStrategy contextStrategy=index.getContextStrategy();
for(Result result:query.execute(10)) {
System.out.println("line:"+result.getLine());
System.out.println("ctx:"+contextStrategy.getContext(result));
}

Link to comment
Share on other sites

La question exacte est donc : "pouvez-vous m'aider".

La réponse est : oui.

Par contre, faire ton TP à ta place : non.

As-tu un problème particulier que tu n'arrives pas à résoudre ?

Salut,

j'aimerais savoir comment m'y prendre pour contruire l'arbre qui servira à faire les recherches ainsi que le codage de la méthode execute.

J'essaye mais je n'arrive pas à savoir comment coder cela.

Link to comment
Share on other sites

Tu utilises String.split() pour découper ta requête (s'il y a un espace entre chaque élément), puis tu utilises le résultat comme une pile (éventuellement, transforme le String[] en LinkedList, qui implémente Queue).

Ensuite, tu dépiles :

- Si c'est un élément simple, tu commences à créer ton enchaînement de Queries.

- Si c'est un opérateur (| ou &), tu dépiles aussi les deux suivants, qui sont tes opérandes.

A la fin tu as donc ton arbre de Query, comme ton code :

Query query=factory.and(factory2.query("God"), factory.query("solid"));

Et il ne reste plus qu'à l'exécuter :)

Link to comment
Share on other sites

Tu utilises String.split() pour découper ta requête (s'il y a un espace entre chaque élément), puis tu utilises le résultat comme une pile (éventuellement, transforme le String[] en LinkedList, qui implémente Queue).

Ensuite, tu dépiles :

- Si c'est un élément simple, tu commences à créer ton enchaînement de Queries.

- Si c'est un opérateur (| ou &), tu dépiles aussi les deux suivants, qui sont tes opérandes.

A la fin tu as donc ton arbre de Query, comme ton code :

Query query=factory.and(factory2.query("God"), factory.query("solid"));

Et il ne reste plus qu'à l'exécuter :)

J'ai pas très bien compris comment il fallait procéder.

Pourrais-tu s'il te plait me détailler la partie dépilement

Merci

Link to comment
Share on other sites

Bon, j'ai bricolé un exemple vite fait...

(je tasse un peu le code dans mon post pour des raisons de place...)

J'ai une interface IMatcher qui se charge de dire si le texte donné est "bon" :

public interface IMatcher
{
public boolean matches(String value);
}

Ensuite j'ai plusieurs Matchers spécialisés qui implémentent cette interface. Certains sont des matchers "simples" (qui travaillent sur une simple chaîne de référence) :

public class ContainsMatcher implements IMatcher
{
private final String reference;	

public ContainsMatcher(String reference)
{	this.reference = reference;
}

public boolean matches(String value)
{	return value.contains(reference);
}
}

Et certains sont "composites" (ils utilisent d'autres matchers pour déterminer si le texte est "bon") :

public class AndMatcher implements IMatcher
{
private final IMatcher matcher1;
private final IMatcher matcher2;

public AndMatcher(IMatcher matcher1, IMatcher matcher2)
{
	this.matcher1 = matcher1;
	this.matcher2 = matcher2;
}

public boolean matches(String value)
{	return ( matcher1.matches(value) && matcher2.matches(value) );
}
}

Ensuite, j'ai une MatcherFactory, à qui on donne l'expression de recherche ("& titi toto"), et qui se charge de l'analyser et de construire la hiérarchie des Matchers correspondante :

public class MatcherFactory
{
// C'est la méthode publique que notre programme va appeler
public static IMatcher createMatcher(String pattern)
{
	ArrayList<String> expList = new ArrayList<String>(Arrays.asList(pattern.split("\\s+")));
	return getSpecializedMatcher(expList);
}

// Méthode récursive, qui lit le premier élément de la liste des expressions, et
// renvoie le Matcher correspondant.
private static IMatcher getSpecializedMatcher(List<String> expList)
{
	String exp = expList.remove(0);
	if ("&".equals(exp))
	{
		IMatcher operand1 = getSpecializedMatcher(expList);
		IMatcher operand2 = getSpecializedMatcher(expList);
		return new AndMatcher(operand1, operand2);
	}
	else if ("|".equals(exp))
	{
		IMatcher operand1 = getSpecializedMatcher(expList);
		IMatcher operand2 = getSpecializedMatcher(expList);
		return new OrMatcher(operand1, operand2);
	}
	else if (exp.startsWith("@"))
	{	return new RegexMatcher(exp.substring(1));
	}
	else if (exp.startsWith("!"))
	{	return new ExactMatcher(exp.substring(1));
	}
	else
	{	return new ContainsMatcher(exp);
	}		
}
}

Après ça il ne reste plus qu'à écrire un petit programme de test, qui va lire les lignes d'un fichier une à une, et les tester grâce au Matcher fourni par la MatcherFactory. Les lignes considérées comme "bonnes" sont simplement affichées à l'écran :

public class Parser
{	
public static void main(String... args) throws IOException
{
	//String pattern = "titi";
	//String pattern = "!titi";
	//String pattern = "& titi toto";
	//String pattern = "| titi toto";
	String pattern = "& titi @.*parti.*|.*revenu.*";
	new Parser(new File("test.txt"), pattern);
}

public Parser(File file, String expression) throws IOException
{
	IMatcher matcher = MatcherFactory.createMatcher(expression);
	searchInFile(file, matcher);
}	

private void searchInFile(File file, IMatcher matcher) throws IOException
{
	String line = null;		
	LineNumberReader reader = new LineNumberReader(new FileReader(file));
	while ((line=reader.readLine()) != null)
	{
		if (matcher.matches(line))
		{	System.out.println("#" + reader.getLineNumber() + " : " + line);
		}
	}
	reader.close();		
}
}

Le fichier de test est simple également, mais se prête bien aux expressions rationnelles :)

toto
titi
tata
tutu
toto est parti
toto est revenu
titi est aussi parti
mais titi n'est pas revenu
123456
__123456__

Voilà donc comment on peut "parser" facilement une expression...

Si tu veux je t'envoie mon projet Java complet, pour que tu puisses jouer avec et voir les différents Matchers que j'ai inventés pour rigoler :byebye:

Je sais que ça ne correspond pas exactement à tes interfaces prédéfinies, mais tu as tout le principe sous les yeux, il suffit d'adapter mon code.

Sentinel

Link to comment
Share on other sites

Au lieu de créer des Matchers avec l'opérateur "new", il faut appeler ta QueryFactory pour qu'elle te renvoie le bon Matcher.

return new AndMatcher(...) => return QueryFactory.and(...)

Mais bon, j'avoue que tes interfaces sont assez moisies. Qui t'a pondu ça, un prof ? Et tous ces pseudo-patterns (façade, stratégie) mal utilisés, ça fait peine à voir...

Link to comment
Share on other sites

Au lieu de créer des Matchers avec l'opérateur "new", il faut appeler ta QueryFactory pour qu'elle te renvoie le bon Matcher.

return new AndMatcher(...) => return QueryFactory.and(...)

Mais bon, j'avoue que tes interfaces sont assez moisies. Qui t'a pondu ça, un prof ? Et tous ces pseudo-patterns (façade, stratégie) mal utilisés, ça fait peine à voir...

Les changements que tu indiques sont à faire dans la fonction qui fait la recherche (la méthode execute dans mon cas) mais ce que je n'arrive pas à adapter ce sont les méthodes query, query and, query or.

Link to comment
Share on other sites

Je vais t'aider dans ta réflexion... Le matcher OR est "valide" si au moins un des deux sous-matchers déclare la chaîne testée "valide".

- Dans mon implémentation, les valeurs de retour des matchers sont des booléens, je peux donc me contenter d'un simple opérateur || pour tester le OR.

- Dans ton implémentation, un matcher renvoie des Itérateurs : une chaîne est déclarée valide si le matcher la renvoie comme résultat.

A partir de là, en poursuivant la réflexion, tu devrais pouvoir trouver la solution :)

Link to comment
Share on other sites

Je remets les interfaces qu'il faut implémenter et un exemple d'utilisation pour tout visualiser

import java.io.File;
import java.io.IOException;
import java.io.Reader;

import java.util.Map;
import java.util.regex.Pattern;


public interface FoogleFacade {
 public Index loadIndex(File indexFile)  throws IOException;

 public QueryFactory createQueryFactory(Index index);

}

public interface Index {
 public String getFilename();
}

public interface Query {
 public Iterable<? extends Result> execute();

 public Iterable<? extends Result> execute(int maxCount);
}

import java.util.regex.Pattern;

public interface QueryFactory {

 public Query query(CharSequence word);

 public Query query(Pattern pattern);

 public Query or(Query query1,Query query2);

 public Query and(Query query1,Query query2);
}

public interface Result {
 public int getLine();
}

pour pouvoir avoir comme main ceci:

FoogleFacade foogle = new FoogleFacadeImpl();

Index index=foogle.loadIndex(new File("bbe.idx"));
System.out.println("indexed filename:"+index.getFilename());

QueryFactory factory=foogle.createQueryFactory(index);
Query query=factory.and(factory2.query("God"),factory.query("solid"));

for(Result result:query.execute(10)) {
System.out.println("line:"+result.getLine());
}

Ce que j'ai codé :

public class IndexImpl implements Index{
 String filename = "";

public IndexImpl(String filename){
 super();
 this.filename = filename;
}

public String getFileName(){
 return filename;
}
}

et ensuite pour retourner l'index depuis ta méthode load, il faut que tu crée un objet index avec en paramètre le chemin du fichier : 

[CODE]
public class FoogleFacadeImpl implements FoogleFacade{
public Index loadIndex(File indexFile)  throws IOException{
   Index index = new IndexImpl(indexFile.getAbsolutePath());
   return index;
}
//   public QueryFactory createQueryFactory(Index index);
}

La ça se complique car j'ai mélangé les Query et les QueryFactory mais je n'arrive pas à faire les séparartions nécessaire.

Je n'arrive également pas à implémenter le ET et le OU

public class ResultImpl implements Result{
private List<Integer> list;

 public ResultImpl(String linenumber){
 list.add(linenumber);
 }

  public int getLine(){...}
}

public Iterable<? implements Result> values(Pattern pattern){
	File file;
	String line = null;
	Result result;
	ArrayList<Result> list= new ArrayList<Result>();		
	LineNumberReader reader = new LineNumberReader(new FileReader(file));
	while ((line=reader.readLine()) != null)
	{
	if(pattern.matcher(line))
			result = new Result(reader.getLineNumber());
			list.add(result);
	}
	reader.close();
  return list;		
}
}

Link to comment
Share on other sites

Ben, c'est pourtant simple...

ET : les résultats qui sont dans A ET B

OU : les résultats qui sont dans A OU B...

Là vraiment je peux pas te dire mieux sans écrire le code à ta place...

Concernant ce que j'ai écrit, pourrais-tu m'aider s'il te plait pour utiliser les Query et QueryFactory comme il est demandé car je n'arrive pas

Link to comment
Share on other sites

Là, je ne peux plus t'aider sans écrire le code à ta place, ce que je ne ferai pas.

Demande des précisions à tes collègues ou à ton prof...

Et relis mes commentaires, tout est dedans !

[EDIT]

En fait, ce qui te perturbe je crois, c'est que tes matchers renvoient des Iterable... Pense au problème comme s'ils renvoyaient des List, par exemple, et tout sera plus simple.

Pense aussi aux portes ET et OU en électronique, ça pourra t'aider.

Link to comment
Share on other sites

Salut,

j'aurais besoin d'aide pour l'écriture d'une fonction.

Voici 2 interfaces :

import java.io.File;
import java.io.IOException;

public interface Facade {
  /** Loads an index stored in a file in memory.
 * @param indexFile file that store the index.
 * @return an in-memory index corresponding to the file.
 * @throws IOException raised if there is input/output problems.
 */
 public Index loadIndex(File indexFile)  throws IOException;
}

import java.io.File;

public interface Index {
/** Returns the name of the indexed file.
  * @return the name of the indexed file.
  */
public String getFilename();
}

que j'ai implémenté de cette manière :

public class IndexImpl implements Index{
String filename = ""; 

 public IndexImpl(String filename){
	super(); 
	this.filename = filename; 
 } 

  public String getFileName(){
	 return filename; 
 } 
}

public class FacadeImpl implements Facade{
public Index loadIndex(File indexFile)  throws IOException{
	String line = null;		

Index index = new IndexImpl(indexFil.getAbsolutePath()); 
LineNumberReader reader = new LineNumberReader(new FileReader(indexFile)); 
while ((line=reader.readLine()) != null) { 
	System.out.println("#" + reader.getLineNumber() + " : " + line); 
	} 
  reader.close(); 
  return index; 
 } 
}

pour pouvoir écrire dans un main ceci :

Facade facade = new FacadeImpl();

Index index=facade.loadIndex(new File("bbe.idx"));
System.out.println("indexed filename:"+index.getFilename());

Le problème est que la méthode loadIndex telle que je l'ai codé ne fait pas ce qui est demandé mais je ne sais pas comment faire ...

Link to comment
Share on other sites

Pourrais-tu dérailler un peu plus ?

Que doit faire ta fonction loadIndex ?

Quel comportement a-t-elle maintenant ?

As-tu fait un debug sur ta méthode ?

 /** Loads an index stored in a file in memory.
 * @param indexFile file that store the index.
 * @return an in-memory index corresponding to the file.
 * @throws IOException raised if there is input/output problems.
 */
 public Index loadIndex(File indexFile)  throws IOException;

Cette méthode prend un fichier en parametre et renvoit un index en mémoire contenant ce fichier

Ce que j'ai écrit ne donne que le chemin d'accès au fichier or ce n'est pas ce qu'il faut .

Dans cette même interface, il me faut implémenter aussi cette méthode

 /** Returns a query factory specific to an index
  * @param index the queries will be created on this index
  * @return a new query factory
  */
 public QueryFactory createQueryFactory(Index index);

qui utilisera l'index obtenu pour effectuer des requetes sur dessus

QueryFactory est une interface :

import java.util.regex.Pattern;

/** Factory used to create index queries,
*  The factory is specific to an index.
*
*/
public interface QueryFactory {
 /** Creates a query for a simple word.
  * 
  * @param word the queried word.
  * @return a new query.
  */
 public Query query(CharSequence word);

 /** Creates a query for a regex.
  * 
  * @param pattern the queried regex.
  * @return a new query.
  */
 public Query query(Pattern pattern);

 /** Create a new query by oring query1 and query2.
  *  
  * @param query1 the first query.
  * @param query2 the second query.
  * @return the new query.
  */
 public Query or(Query query1,Query query2);

 /** Create a new query by anding query1 and query2.
  * @param query1 the first query.
  * @param query2 the second query.
  * @return the new query.
  */
 public Query and(Query query1,Query query2);
}

Link to comment
Share on other sites

En faite le souci que j'ai est qu'avec ce que j'ai écrit, je ne sais pas comment accéder aux données du fichier pour utiliser les méthodes de QueryFactory.

Sans accès aux données, je ne peux pas faire de recherches....

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Guest
This topic is now closed to further replies.
×
×
  • Create New...