Skip to content

Commit

Permalink
DidYouMean - changed to much simpler LinkedBlockingQueue
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@6071 6c8d7289-2bf4-0310-a012-ef5d649a1542
  • Loading branch information
apfelmaennchen committed Jun 14, 2009
1 parent 01ac1b5 commit c3c4dd0
Showing 1 changed file with 73 additions and 105 deletions.
178 changes: 73 additions & 105 deletions source/de/anomic/tools/DidYouMean.java
Expand Up @@ -2,8 +2,8 @@

import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;

import de.anomic.kelondro.text.IndexCell;
import de.anomic.kelondro.text.referencePrototype.WordReference;
Expand All @@ -23,192 +23,160 @@ public class DidYouMean {
'q','r','s','t','u','v','w','x','y','z','\u00e4','\u00f6','\u00fc','\u00df'};
private static final long TIMEOUT = 500;

final LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>();

private final Set<String> set;
private final IndexCell<WordReference> index;
private String word;
private int len;

private Thread ChangingOneLetter;
private Thread AddingOneLetter;
private Thread DeletingOneLetter;
private Thread ReversingTwoConsecutiveLetters;

private final BlockingQueue bq = new BlockingQueue();

public DidYouMean(final IndexCell<WordReference> index) {
// this.set = Collections.synchronizedSortedSet(new TreeSet<String>(new wordSizeComparator()));
this.set = Collections.synchronizedSet(new HashSet<String>());
this.word = "";
this.len = 0;
this.index = index;

this.ChangingOneLetter = new ChangingOneLetter();
this.AddingOneLetter = new AddingOneLetter();
this.DeletingOneLetter = new DeletingOneLetter();
this.ReversingTwoConsecutiveLetters = new ReversingTwoConsecutiveLetters();
}

public Set<String> getSuggestion(final String word) {
long startTime = System.currentTimeMillis();
this.word = word.toLowerCase();
this.len = word.length();

// create worker threads
Thread[] workers = new Thread[8];
for (int i=0; i<workers.length; i++) {
workers[i] = new Worker("WorkerThread_"+i);
}
// first push the tasks for calculation of word variations on blocking queue
bq.push(this.ChangingOneLetter);
bq.push(this.AddingOneLetter);
bq.push(this.DeletingOneLetter);
bq.push(this.ReversingTwoConsecutiveLetters);

// check for timeout
boolean run = true;
while(run && (System.currentTimeMillis()-startTime) < TIMEOUT) {
if(bq.size() > 0) {
run = true;
} else {
run = false;
}
// create producers
Thread[] producers = new Thread[4];
producers[0] = new ChangingOneLetter();
producers[1] = new AddingOneLetter();
producers[2] = new DeletingOneLetter();
producers[3] = new ReversingTwoConsecutiveLetters();

// start producers
for (int i=0; i<producers.length; i++) {
producers[i].start();
}

// create and start 8 consumers threads
Thread[] consumers = new Thread[8];
for (int i=0; i<consumers.length; i++) {
consumers[i] = new Consumer();
consumers[i].start();
}

// check if timeout has been reached
while(((System.currentTimeMillis()-startTime) < TIMEOUT) && queue.size()>0) {
// consume more ...
}

// push "poison pill" for each worker thread
for (int i=0; i<workers.length; i++) {
bq.push(new Thread() {
public void run() {
Thread.currentThread().interrupt();
}
});
// put "poison pill" for each consumer thread
for (int i=0; i<consumers.length; i++) {
try {
queue.put("\n");
} catch (InterruptedException e) {
}
}

// interupt all remaining producer threads
for (int i=0; i<producers.length; i++) {
producers[i].interrupt();
}

this.set.remove(word.toLowerCase());
Log.logInfo("DidYouMean", "found "+this.set.size()+" terms; execution time: "
+(System.currentTimeMillis()-startTime)+"ms"+ (run?"(timed out)":""));
+(System.currentTimeMillis()-startTime)+"ms"+ (queue.size()>0?"(timed out)":""));

return this.set;

}

private class ChangingOneLetter extends Thread {

public ChangingOneLetter() {
this.setName("ChangingOneLetter");
}

// tests: alphabet.length * len
public void run() {
String s;
for(int i=0; i<len; i++) {
for(int j=0; j<alphabet.length; j++) {
s = word.substring(0, i) + alphabet[j] + word.substring(i+1);
bq.push(new Tester(s));
try {
queue.put(s);
} catch (InterruptedException e) {
return;
}
}
}
}
}

private class DeletingOneLetter extends Thread {

public DeletingOneLetter() {
this.setName("DeletingOneLetter");
}

// tests: len
public void run() {
String s;
for(int i=0; i<len;i++) {
s = word.substring(0, i) + word.substring(i+1);
bq.push(new Tester(s));
try {
queue.put(s);
} catch (InterruptedException e) {
return;
}
}
}
}

private class AddingOneLetter extends Thread {

public AddingOneLetter() {
this.setName("AddingOneLetter");
}

// tests: alphabet.length * len
public void run() {
String s;
for(int i=0; i<=len;i++) {
for(int j=0; j<alphabet.length; j++) {
s = word.substring(0, i) + alphabet[j] + word.substring(i);
bq.push(new Tester(s));
try {
queue.put(s);
} catch (InterruptedException e) {
return;
}
}
}
}
}

private class ReversingTwoConsecutiveLetters extends Thread {

public ReversingTwoConsecutiveLetters() {
this.setName("ReversingTwoConsecutiveLetters");
}


// tests: (len - 1)
public void run() {
String s;
for(int i=0; i<len-1; i++) {
s = word.substring(0,i)+word.charAt(i+1)+word.charAt(i)+word.substring(i+2);
bq.push(new Tester(s));
}
}
}

private class Tester extends Thread {

private String s;

public Tester(String s) {
this.s = s;
}
public void run() {
if (index.has(Word.word2hash(s))) {
set.add(s);
try {
queue.put(s);
} catch (InterruptedException e) {
return;
}
}
}
}

private class Worker extends Thread {
public Worker(String name) {
super(name);
start();
}

class Consumer extends Thread {

public void run() {
try {
while(!isInterrupted()) {
((Runnable)bq.pop()).run();
while(true) {
String s = (String)queue.take();
if(s.equals("\n"))
this.interrupt();
else
consume(s);
}
} catch(InterruptedException e) {
}
}
}

private class BlockingQueue {
private final LinkedList<Thread> queue = new LinkedList<Thread>();

public void push(Thread t) {
synchronized(queue) {
queue.add(t);
queue.notify();
} catch (InterruptedException e) {
return;
}
}
public Object pop() throws InterruptedException {
synchronized(queue) {
while (queue.isEmpty()) {
queue.wait();
}
return queue.removeFirst();
void consume(String s) {
if (index.has(Word.word2hash(s))) {
set.add(s);
}
}
public int size() {
return queue.size();
}
}
}

/*
private class wordSizeComparator implements Comparator<String> {
Expand Down

0 comments on commit c3c4dd0

Please sign in to comment.