mirror of https://github.com/kiwix/libkiwix.git
Catalog filtering by creator works via Xapian
This commit is contained in:
parent
d3d5abe14d
commit
3d5fd8f585
|
@ -123,6 +123,9 @@ class Filter {
|
||||||
bool hasPublisher() const;
|
bool hasPublisher() const;
|
||||||
const std::string& getPublisher() const { return _publisher; }
|
const std::string& getPublisher() const { return _publisher; }
|
||||||
|
|
||||||
|
bool hasCreator() const;
|
||||||
|
const std::string& getCreator() const { return _creator; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Library;
|
friend class Library;
|
||||||
|
|
||||||
|
|
|
@ -281,12 +281,14 @@ void Library::updateBookDB(const Book& book)
|
||||||
const std::string name = book.getName(); // this is supposed to be normalized
|
const std::string name = book.getName(); // this is supposed to be normalized
|
||||||
const std::string category = book.getCategory(); // this is supposed to be normalized
|
const std::string category = book.getCategory(); // this is supposed to be normalized
|
||||||
const std::string publisher = normalizeText(book.getPublisher());
|
const std::string publisher = normalizeText(book.getPublisher());
|
||||||
|
const std::string creator = normalizeText(book.getCreator());
|
||||||
doc.add_value(0, title);
|
doc.add_value(0, title);
|
||||||
doc.add_value(1, desc);
|
doc.add_value(1, desc);
|
||||||
doc.add_value(2, name);
|
doc.add_value(2, name);
|
||||||
doc.add_value(3, category);
|
doc.add_value(3, category);
|
||||||
doc.add_value(4, lang);
|
doc.add_value(4, lang);
|
||||||
doc.add_value(5, publisher);
|
doc.add_value(5, publisher);
|
||||||
|
doc.add_value(6, creator);
|
||||||
doc.set_data(book.getId());
|
doc.set_data(book.getId());
|
||||||
|
|
||||||
indexer.index_text(title, 1, "S");
|
indexer.index_text(title, 1, "S");
|
||||||
|
@ -295,6 +297,7 @@ void Library::updateBookDB(const Book& book)
|
||||||
indexer.index_text(category, 1, "XC");
|
indexer.index_text(category, 1, "XC");
|
||||||
indexer.index_text(lang, 1, "L");
|
indexer.index_text(lang, 1, "L");
|
||||||
indexer.index_text(publisher, 1, "XP");
|
indexer.index_text(publisher, 1, "XP");
|
||||||
|
indexer.index_text(creator, 1, "A");
|
||||||
|
|
||||||
// Index fields without prefixes for general search
|
// Index fields without prefixes for general search
|
||||||
indexer.index_text(title);
|
indexer.index_text(title);
|
||||||
|
@ -331,6 +334,7 @@ Xapian::Query buildXapianQueryFromFilterQuery(const Filter& filter)
|
||||||
queryParser.add_prefix("category", "XC");
|
queryParser.add_prefix("category", "XC");
|
||||||
queryParser.add_prefix("lang", "L");
|
queryParser.add_prefix("lang", "L");
|
||||||
queryParser.add_prefix("publisher", "XP");
|
queryParser.add_prefix("publisher", "XP");
|
||||||
|
queryParser.add_prefix("creator", "A");
|
||||||
const auto partialQueryFlag = filter.queryIsPartial()
|
const auto partialQueryFlag = filter.queryIsPartial()
|
||||||
? Xapian::QueryParser::FLAG_PARTIAL
|
? Xapian::QueryParser::FLAG_PARTIAL
|
||||||
: 0;
|
: 0;
|
||||||
|
@ -371,6 +375,16 @@ Xapian::Query publisherQuery(const std::string& publisher)
|
||||||
return Xapian::Query(Xapian::Query::OP_PHRASE, q.get_terms_begin(), q.get_terms_end(), q.get_length());
|
return Xapian::Query(Xapian::Query::OP_PHRASE, q.get_terms_begin(), q.get_terms_end(), q.get_length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Xapian::Query creatorQuery(const std::string& creator)
|
||||||
|
{
|
||||||
|
Xapian::QueryParser queryParser;
|
||||||
|
queryParser.set_default_op(Xapian::Query::OP_OR);
|
||||||
|
queryParser.set_stemming_strategy(Xapian::QueryParser::STEM_NONE);
|
||||||
|
const auto flags = 0;
|
||||||
|
const auto q = queryParser.parse_query(normalizeText(creator), flags, "A");
|
||||||
|
return Xapian::Query(Xapian::Query::OP_PHRASE, q.get_terms_begin(), q.get_terms_end(), q.get_length());
|
||||||
|
}
|
||||||
|
|
||||||
Xapian::Query buildXapianQuery(const Filter& filter)
|
Xapian::Query buildXapianQuery(const Filter& filter)
|
||||||
{
|
{
|
||||||
auto q = buildXapianQueryFromFilterQuery(filter);
|
auto q = buildXapianQueryFromFilterQuery(filter);
|
||||||
|
@ -386,6 +400,9 @@ Xapian::Query buildXapianQuery(const Filter& filter)
|
||||||
if ( filter.hasPublisher() ) {
|
if ( filter.hasPublisher() ) {
|
||||||
q = Xapian::Query(Xapian::Query::OP_AND, q, publisherQuery(filter.getPublisher()));
|
q = Xapian::Query(Xapian::Query::OP_AND, q, publisherQuery(filter.getPublisher()));
|
||||||
}
|
}
|
||||||
|
if ( filter.hasCreator() ) {
|
||||||
|
q = Xapian::Query(Xapian::Query::OP_AND, q, creatorQuery(filter.getCreator()));
|
||||||
|
}
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,6 +715,11 @@ bool Filter::hasPublisher() const
|
||||||
return ACTIVE(_PUBLISHER);
|
return ACTIVE(_PUBLISHER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Filter::hasCreator() const
|
||||||
|
{
|
||||||
|
return ACTIVE(_CREATOR);
|
||||||
|
}
|
||||||
|
|
||||||
bool Filter::accept(const Book& book) const
|
bool Filter::accept(const Book& book) const
|
||||||
{
|
{
|
||||||
auto local = !book.getPath().empty();
|
auto local = !book.getPath().empty();
|
||||||
|
@ -713,7 +735,6 @@ bool Filter::accept(const Book& book) const
|
||||||
FILTER(_NOREMOTE, !remote)
|
FILTER(_NOREMOTE, !remote)
|
||||||
|
|
||||||
FILTER(MAXSIZE, book.getSize() <= _maxSize)
|
FILTER(MAXSIZE, book.getSize() <= _maxSize)
|
||||||
FILTER(_CREATOR, book.getCreator() == _creator)
|
|
||||||
|
|
||||||
if (ACTIVE(ACCEPTTAGS)) {
|
if (ACTIVE(ACCEPTTAGS)) {
|
||||||
if (!_acceptTags.empty()) {
|
if (!_acceptTags.empty()) {
|
||||||
|
|
|
@ -472,18 +472,42 @@ TEST_F(LibraryTest, filterByCreator)
|
||||||
"Granblue Fantasy Wiki"
|
"Granblue Fantasy Wiki"
|
||||||
);
|
);
|
||||||
|
|
||||||
// filtering by creator is case sensitive
|
// filtering by creator is case and diacritics insensitive
|
||||||
EXPECT_FILTER_RESULTS(kiwix::Filter().creator("wiki"),
|
EXPECT_FILTER_RESULTS(kiwix::Filter().creator("wIkï"),
|
||||||
/* no results */
|
"Granblue Fantasy Wiki"
|
||||||
);
|
);
|
||||||
|
|
||||||
// filtering by creator requires full match of the full author/creator name
|
// filtering by creator doesn't requires full match of the full creator name
|
||||||
EXPECT_FILTER_RESULTS(kiwix::Filter().creator("Stack"),
|
EXPECT_FILTER_RESULTS(kiwix::Filter().creator("Stack"),
|
||||||
/* no results */
|
"Islam Stack Exchange",
|
||||||
|
"Movies & TV Stack Exchange",
|
||||||
|
"Mythology & Folklore Stack Exchange"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// filtering by creator requires a full phrase match (ignoring some non-word terms)
|
||||||
EXPECT_FILTER_RESULTS(kiwix::Filter().creator("Movies & TV Stack Exchange"),
|
EXPECT_FILTER_RESULTS(kiwix::Filter().creator("Movies & TV Stack Exchange"),
|
||||||
"Movies & TV Stack Exchange"
|
"Movies & TV Stack Exchange"
|
||||||
);
|
);
|
||||||
|
EXPECT_FILTER_RESULTS(kiwix::Filter().creator("Movies & TV"),
|
||||||
|
"Movies & TV Stack Exchange"
|
||||||
|
);
|
||||||
|
EXPECT_FILTER_RESULTS(kiwix::Filter().creator("Movies TV"),
|
||||||
|
"Movies & TV Stack Exchange"
|
||||||
|
);
|
||||||
|
EXPECT_FILTER_RESULTS(kiwix::Filter().creator("TV & Movies"),
|
||||||
|
/* no results */
|
||||||
|
);
|
||||||
|
EXPECT_FILTER_RESULTS(kiwix::Filter().creator("TV Movies"),
|
||||||
|
/* no results */
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_FILTER_RESULTS(kiwix::Filter().query("creator:Wikipedia"),
|
||||||
|
"Encyclopédie de la Tunisie",
|
||||||
|
"Géographie par Wikipédia",
|
||||||
|
"Mathématiques",
|
||||||
|
"Ray Charles"
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LibraryTest, filterByPublisher)
|
TEST_F(LibraryTest, filterByPublisher)
|
||||||
|
|
Loading…
Reference in New Issue