Fluent-Search icon indicating copy to clipboard operation
Fluent-Search copied to clipboard

More predictable web search results

Open razjel opened this issue 2 years ago • 6 comments

I'm migrating from Launchy to Fluent and I have around 200 web search entries. When I try to search for any entry in web search it always lists first 15 of entries from web settings. It looks like it doesn't filter them based on what I write in search input.

image

In Launchy this works great because searching is looking for matching words and can filter entries very efficiently. Is it possible to have something similiar in fluenty?

image

razjel avatar Jul 15 '22 14:07 razjel

Hey @razjel, to filter results in Fluent Search you use Search Tags. Web search will create tags automatically for your web searches, and you can decide the tag using the Tag column in web searches - image

To use a search tag, simply start typing it's name and press TAB - image

In addition, to make the behavior a bit more like Launchy, you can use Keyword mode in Settings -> Search tags, that will let you search using tags without pressing TAB, so if your tag is for Google is g, then you can do g my search to search in Google - image

Let me know if it helps.

adirh3 avatar Jul 15 '22 15:07 adirh3

I already have tags defined. Inside main input indeed it suggests me most matching entry but it only suggests first one. In situation when I have similiar ones I can't easily see them like in launchy, f.e. in fluent I see only rpg advanced names in launchy I see all options and can switch easily between them using down and up.

image

image

I set keyword mode in Search tags options but it doesn't change way search behaves. I even restarted fluenty :<

image

Here are my options:

image

image

razjel avatar Jul 16 '22 11:07 razjel

This issue has been potentially fixed in version 0.9.92.36 . Changelog - https://install.appcenter.ms/users/adirh3-gmail.com/apps/fluent-search-alpha/distribution_groups/exe

adirh3 avatar Aug 18 '22 23:08 adirh3

I really appreciate you found time to touch my issue :)

I tested it. It's much better but Launchy still handles it better for my use cases. With this version Fluent matches beginnings of tags to input from search field, but it only matches whole words and it looks like it can't skip words in between. Launchy allows to seek in any words and matching fragments of words.

Also I don't know if it's a bug, but it worked with fresh entries I added for the purpose of test but after I edited one of them it stopped being found. I don't know if it's because of fact I edited it or it's data is somehow causing Fluent to skip it.

image

image

image

razjel avatar Aug 19 '22 20:08 razjel

@razjel thanks for the input! If you match part of a word, how would you know if that's what the user intended to search or it's part of a tag? I tried implementing it that way at the beginning, but it seems very confusing for me.

I think I do not fully understand the use cases here. TBH I never used Launchy and I don't really understand what I am seeing in that screenshot (sorry). I would appreciate it if you could describe what the use cases are with examples of input/output.

adirh3 avatar Aug 19 '22 21:08 adirh3

It's hard to describe with with words so I've written example implementation in JS. Launchy is doing a bit more with this, because it remembers which option you were choosing previously for given query and moves those entries to higher positions in final result.

function inteligentSearch(query, entries) {
	let filteredEntries = entries.map((text) => {
		return {text: text, lastIdx: -1, allFoundedIndexes: []};
	});

	const lowerCaseQuery = query.toLowerCase();
	for (let i = 0; i < lowerCaseQuery.length; i++) {
		const queryChar = lowerCaseQuery.charAt(i);
		filteredEntries = filteredEntries.map((entry) => {
			if (entry.text.charAt(entry.lastIdx + 1).toLowerCase() === queryChar) {
				const resultIdx = entry.lastIdx + 1;
				return {
					text: entry.text,
					lastIdx: resultIdx,
					allFoundedIndexes: entry.allFoundedIndexes.concat(resultIdx),
				};
			} else {
				const furtherText = entry.text.substring(entry.lastIdx + 1);
				const foundIdx = furtherText.toLowerCase().search(queryChar);
				if (foundIdx !== -1) {
					const resultIdx = foundIdx + entry.lastIdx + 1;
					return {
						text: entry.text,
						lastIdx: resultIdx,
						allFoundedIndexes: entry.allFoundedIndexes.concat(resultIdx),
					};
				}
			}
		});
		filteredEntries = filteredEntries.filter((entry) => {
			return !!entry;
		});
	}
	return filteredEntries;
}

function test(query, entries, expected) {
	const result = inteligentSearch(query, entries);
	try {
		if (result.length !== expected.length) {
			throw 1;
		}
		for (let i = 0; i < result.length; i++) {
			if (result[i].text !== expected[i].text) {
				throw 1;
			}
			if (JSON.stringify(result[i].allFoundedIndexes) !== JSON.stringify(expected[i].allFoundedIndexes)) {
				throw 1;
			}
		}
		console.log("succes");
	} catch (error) {
		console.log("failed: \n" + JSON.stringify(result) + "\n" + JSON.stringify(expected));
	}
}

test(
	"rpro",
	["rpg roll20 net", "rpg spell roam"],
	[
		{text: "rpg roll20 net", allFoundedIndexes: [0, 1, 4, 5]},
		{
			text: "rpg spell roam",
			allFoundedIndexes: [0, 1, 10, 11],
		},
	]
);

test("rprol", ["rpg roll20 net", "rpg spell roam"], [{text: "rpg roll20 net", allFoundedIndexes: [0, 1, 4, 5, 6]}]);

razjel avatar Sep 08 '22 22:09 razjel