Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ft search #5567

Merged
merged 7 commits into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions src/common/expression/Expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -512,10 +512,7 @@ Expression* Expression::decode(ObjectPool* pool, Expression::Decoder& decoder) {
exp->resetFrom(decoder);
return exp;
}
case Expression::Kind::kTSPrefix:
case Expression::Kind::kTSWildcard:
case Expression::Kind::kTSRegexp:
case Expression::Kind::kTSFuzzy: {
case Expression::Kind::kESQUERY: {
LOG(FATAL) << "Should not decode text search expression";
return exp;
}
Expand Down Expand Up @@ -721,17 +718,8 @@ std::ostream& operator<<(std::ostream& os, Expression::Kind kind) {
case Expression::Kind::kPathBuild:
os << "PathBuild";
break;
case Expression::Kind::kTSPrefix:
os << "Prefix";
break;
case Expression::Kind::kTSWildcard:
os << "Wildcard";
break;
case Expression::Kind::kTSRegexp:
os << "Regexp";
break;
case Expression::Kind::kTSFuzzy:
os << "Fuzzy";
case Expression::Kind::kESQUERY:
os << "ESQuery";
break;
case Expression::Kind::kListComprehension:
os << "ListComprehension";
Expand Down
5 changes: 1 addition & 4 deletions src/common/expression/Expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,7 @@ class Expression {

kPathBuild,
// text or key word search expression
kTSPrefix,
kTSWildcard,
kTSRegexp,
kTSFuzzy,
kESQUERY,

kAggregate,
kIsNull,
Expand Down
45 changes: 15 additions & 30 deletions src/common/expression/TextSearchExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,25 @@
namespace nebula {

bool TextSearchArgument::operator==(const TextSearchArgument& rhs) const {
return val_ == rhs.val_ && op_ == rhs.op_ && fuzziness_ == rhs.fuzziness_ &&
limit_ == rhs.limit_ && timeout_ == rhs.timeout_;
return index_ == rhs.index_ && query_ == rhs.query_ && props_ == rhs.props_;
}

std::string TextSearchArgument::toString() const {
std::string buf;
buf.reserve(64);
buf = from_ + "." + prop_ + ", ";
buf += "\"" + val_ + "\"";
if (fuzziness_ == -1) {
buf += ", AUTO, ";
buf += ((op_ == "or") ? "OR" : "AND");
} else if (fuzziness_ > -1) {
buf += ", ";
buf += folly::stringPrintf("%d, ", fuzziness_);
buf += ((op_ == "or") ? "OR" : "AND");
if (!index_.empty()) {
buf += "\"" + index_ + "\", ";
}
if (limit_ != -1) {
buf += folly::stringPrintf(", %d", limit_);
}
if (timeout_ != -1) {
buf += folly::stringPrintf(", %d", timeout_);
buf += "\"" + query_ + "\"";
if (!props_.empty()) {
buf += ", [";
for (size_t i = 0; i < props_.size(); i++) {
buf += props_[i];
if (i != props_.size() - 1) {
buf += ", ";
}
}
buf += "]";
}
return buf;
}
Expand All @@ -49,20 +46,8 @@ std::string TextSearchExpression::toString() const {
std::string buf;
buf.reserve(64);
switch (kind_) {
case Kind::kTSWildcard: {
buf = "WILDCARD(";
break;
}
case Kind::kTSPrefix: {
buf = "PREFIX(";
break;
}
case Kind::kTSFuzzy: {
buf = "FUZZY(";
break;
}
case Kind::kTSRegexp: {
buf = "REGEXP(";
case Kind::kESQUERY: {
buf = "ES_QUERY(";
break;
}
default: {
Expand Down
94 changes: 28 additions & 66 deletions src/common/expression/TextSearchExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,60 +14,32 @@ namespace nebula {
class TextSearchArgument final {
public:
static TextSearchArgument* make(ObjectPool* pool,
const std::string& from,
const std::string& prop,
const std::string& val) {
return pool->makeAndAdd<TextSearchArgument>(from, prop, val);
const std::string& index,
const std::string& query,
const std::vector<std::string>& props) {
return pool->makeAndAdd<TextSearchArgument>(index, query, props);
}

~TextSearchArgument() = default;

void setVal(const std::string& val) {
val_ = val;
std::string& index() {
return index_;
}

const std::string& from() {
return from_;
std::string& query() {
return query_;
}

const std::string& prop() {
return prop_;
std::vector<std::string>& props() {
return props_;
}

const std::string& val() const {
return val_;
int64_t& offset() {
return offset_;
}

void setOP(const std::string& op) {
op_ = op;
}

const std::string& op() const {
return op_;
}

void setFuzziness(int32_t fuzz) {
fuzziness_ = fuzz;
}

int32_t fuzziness() {
return fuzziness_;
}

void setLimit(int32_t limit) {
limit_ = limit;
}

int32_t limit() {
return limit_;
}

void setTimeout(int32_t timeout) {
timeout_ = timeout;
}

int32_t timeout() {
return timeout_;
int64_t& count() {
return count_;
}

bool operator==(const TextSearchArgument& rhs) const;
Expand All @@ -76,35 +48,23 @@ class TextSearchArgument final {

private:
friend ObjectPool;
TextSearchArgument(const std::string& from, const std::string& prop, const std::string& val)
: from_(from), prop_(prop), val_(val) {}
TextSearchArgument(const std::string& index,
const std::string& query,
const std::vector<std::string>& props)
: index_(index), query_(query), props_(props) {}

private:
std::string from_;
std::string prop_;
std::string val_;
std::string op_;
int32_t fuzziness_{-2};
int32_t limit_{10000};
int32_t timeout_{-1};
std::string index_;
std::string query_;
std::vector<std::string> props_;
int64_t count_ = 0;
int64_t offset_ = 0;
};

class TextSearchExpression : public Expression {
public:
static TextSearchExpression* makePrefix(ObjectPool* pool, TextSearchArgument* arg) {
return pool->makeAndAdd<TextSearchExpression>(pool, Kind::kTSPrefix, arg);
}

static TextSearchExpression* makeWildcard(ObjectPool* pool, TextSearchArgument* arg) {
return pool->makeAndAdd<TextSearchExpression>(pool, Kind::kTSWildcard, arg);
}

static TextSearchExpression* makeRegexp(ObjectPool* pool, TextSearchArgument* arg) {
return pool->makeAndAdd<TextSearchExpression>(pool, Kind::kTSRegexp, arg);
}

static TextSearchExpression* makeFuzzy(ObjectPool* pool, TextSearchArgument* arg) {
return pool->makeAndAdd<TextSearchExpression>(pool, Kind::kTSFuzzy, arg);
static TextSearchExpression* makeQuery(ObjectPool* pool, TextSearchArgument* arg) {
return pool->makeAndAdd<TextSearchExpression>(pool, Kind::kESQUERY, arg);
}

static TextSearchExpression* make(ObjectPool* pool, Kind kind, TextSearchArgument* arg) {
Expand All @@ -125,7 +85,9 @@ class TextSearchExpression : public Expression {
std::string toString() const override;

Expression* clone() const override {
auto arg = TextSearchArgument::make(pool_, arg_->from(), arg_->prop(), arg_->val());
auto arg = TextSearchArgument::make(pool_, arg_->index(), arg_->query(), arg_->props());
arg->count() = arg_->count();
arg->offset() = arg_->offset();
return TextSearchExpression::make(pool_, kind_, arg);
}

Expand Down
102 changes: 34 additions & 68 deletions src/common/plugin/fulltext/elasticsearch/ESAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,9 @@ namespace nebula::plugin {

using namespace fmt::literals; // NOLINT

ESQueryResult::Item::Item(const std::string& v, const std::string& t) : vid(v), text(t) {}
ESQueryResult::Item::Item(const std::string& s,
const std::string& d,
int64_t r,
const std::string& t)
: src(s), dst(d), rank(r), text(t) {}
ESQueryResult::Item::Item(const std::string& v, double sc) : vid(v), score(sc) {}
ESQueryResult::Item::Item(const std::string& s, const std::string& d, int64_t r, double sc)
: src(s), dst(d), rank(r), score(sc) {}

void ESBulk::put(const std::string& indexName,
const std::string& vid,
Expand Down Expand Up @@ -68,8 +65,10 @@ void ESAdapter::setClients(std::vector<ESClient>&& clients) {
clients_ = std::move(clients);
}

Status ESAdapter::createIndex(const std::string& name) {
folly::dynamic mappings = folly::parseJson(R"(
Status ESAdapter::createIndex(const std::string& name,
const std::vector<std::string>& fields,
const std::string& analyzer) {
critical27 marked this conversation as resolved.
Show resolved Hide resolved
folly::dynamic obj = folly::parseJson(R"(
{
"mappings":{
"properties":{
Expand All @@ -84,14 +83,21 @@ Status ESAdapter::createIndex(const std::string& name) {
},
"rank": {
"type": "long"
},
"text": {
"type": "keyword"
}
}
}
}
)");
auto& mappings = obj["mappings"];
for (auto& field : fields) {
folly::dynamic f = folly::dynamic::object();
f["type"] = "text";
if (!analyzer.empty()) {
f["analyzer"] = analyzer;
}
mappings["properties"][field] = std::move(f);
}

auto result = randomClient().createIndex(name, mappings);
if (!result.ok()) {
return result.status();
Expand Down Expand Up @@ -181,70 +187,26 @@ Status ESAdapter::bulk(const ESBulk& bulk, bool refresh) {
return Status::Error(folly::toJson(resp));
}

StatusOr<ESQueryResult> ESAdapter::prefix(const std::string& index,
const std::string& pattern,
int64_t size,
int64_t timeout) {
folly::dynamic body = folly::dynamic::object();
body["query"] = folly::dynamic::object();
body["query"]["prefix"] = folly::dynamic::object();
body["query"]["prefix"]["text"] = pattern;
if (size > 0) {
body["size"] = size;
body["from"] = 0;
}
return ESAdapter::query(index, body, timeout);
}

StatusOr<ESQueryResult> ESAdapter::wildcard(const std::string& index,
const std::string& pattern,
int64_t size,
int64_t timeout) {
folly::dynamic body = folly::dynamic::object();
body["query"] = folly::dynamic::object();
body["query"]["wildcard"] = folly::dynamic::object("text", pattern);
if (size > 0) {
body["size"] = size;
body["from"] = 0;
}
return ESAdapter::query(index, body, timeout);
}

StatusOr<ESQueryResult> ESAdapter::regexp(const std::string& index,
const std::string& pattern,
int64_t size,
int64_t timeout) {
StatusOr<ESQueryResult> ESAdapter::queryString(const std::string& index,
const std::string& query,
const std::vector<std::string>& fields,
int64_t from,
int64_t size) {
folly::dynamic body = folly::dynamic::object();
body["query"] = folly::dynamic::object();
body["query"]["regexp"] = folly::dynamic::object("text", pattern);
if (size > 0) {
body["size"] = size;
body["from"] = 0;
body["query"]["query_string"] = folly::dynamic::object();
body["query"]["query_string"]["query"] = query;
body["query"]["query_string"]["fields"] = folly::dynamic::array();
for (auto& field : fields) {
body["query"]["query_string"]["fields"].push_back(field);
}
return ESAdapter::query(index, body, timeout);
}

StatusOr<ESQueryResult> ESAdapter::fuzzy(const std::string& index,
const std::string& pattern,
const std::string& fuzziness,
int64_t size,
int64_t timeout) {
folly::dynamic body = folly::dynamic::object();
body["query"] = folly::dynamic::object();
body["query"]["fuzzy"] = folly::dynamic::object();
body["query"]["fuzzy"]["text"] = folly::dynamic::object("value", pattern)("fuzziness", fuzziness);
if (size > 0) {
body["size"] = size;
body["from"] = 0;
body["from"] = from;
}
return ESAdapter::query(index, body, timeout);
return ESAdapter::query(index, body, 2000);
}

// StatusOr<ESQueryResult> ESAdapter::term(const std::string& index,const std::vector<std::string>&
// words){
// folly::dynamic query = folly::dynamic::object("query",folly::dynam)
// }

StatusOr<ESQueryResult> ESAdapter::match_all(const std::string& index) {
folly::dynamic body = folly::dynamic::object();
body["query"] = folly::dynamic::object();
Expand All @@ -266,7 +228,11 @@ StatusOr<ESQueryResult> ESAdapter::query(const std::string& index,
for (auto& hit : hits) {
auto source = hit["_source"];
ESQueryResult::Item item;
item.text = source["text"].getString();
if (hit["_score"].isInt()) {
item.score = hit["_score"].getInt();
} else if (hit["_score"].isDouble()) {
item.score = hit["_score"].getDouble();
}
item.src = source["src"].getString();
item.dst = source["dst"].getString();
item.rank = source["rank"].getInt();
Expand Down
Loading