Getting the "empty controlled statement found" warning | MetaEditor - mql4

How would I ensure that the following if, else if statement follows the following rule:
"If everything in either /*Condition 1*/ or /*Condition 2*/ is true,thencarry on assessing /*Conditions 3 - 12*/"
At present, I am getting the empty controlled statement found 313 38 compiler error/warning.
if(shiftOneClose < shiftOneOpen){ /*Condition 1*/
if((bearHammer / (shiftOneOpen - shiftOneLow) <= OoTMax))
if((bearHammer / bullNail) <= OoTMax)
if(bearHammer >= Transform(PCM,2)); /*Line 313*/
}
else if(shiftOneClose > shiftOneOpen){ /*Condition 2*/
if((bullHammer / (shiftOneClose - shiftOneLow) <= OoTMax))
if((bullHammer / bullNail) <= OoTMax)
if(bullHammer >= Transform(PCM,2));
}
if.... /*Conditions 3 - 12*/
if....
if....
if....
if....
if....
if....
if....
if....
if....
{
[execute trade]
}

You can use general control structures followed by other programming languages like C++, JAVA.
In case you are unfamiliar:
&& this indicates and
|| this means or
Example:
//--- so in order to make it evaluate conditions 3-12, if only condition 1 or 2 is true
if(condition1 || condition2){
if(condition3 && condition4){ /* so on until 12 */
//--- execute trade
}
}
In order to improve the readability of the code I suggest you move some of the conditions into functions

Q : "How would I ensure that the following if,else if statement follows the following rule:
"If everything in either /*Condition 1*/ or /*Condition 2*/ is true,then carry on assessing /*Conditions 3 - 12*/""
The original code blew up in line 313, because the ;-character terminates a statement-constructor, while there was nothing to "execute" if (either) of the if(){...}else{...}-ed conditions were met (the same problem is in the else{...} part, where is also none {...}-code-block present and the formal-statement constructor gets panic not knowing what to "execute" in either of the if(){...}else{...}-branches, as the statement is formally not complete).
if ( shiftOneClose < shiftOneOpen ) /*Condition 1*/
{
if ( ( bearHammer / ( shiftOneOpen - shiftOneLow ) <= OoTMax ) )
if ( ( bearHammer / bullNail ) <= OoTMax )
if ( bearHammer >= Transform( PCM, 2 ) ); /*Line 313*/
}
So, not telling what to do if conditions get met is the root problem above.
The Solution to the "HOW WOULD I ENSURE ..." part:
A syntactically correct would be this explanatory logic-preserving code template:
if ( ( ( shiftOneClose < shiftOneOpen
&& OoTMax >= ( bearHammer / ( shiftOneOpen - shiftOneLow ) )
&& OoTMax >= ( bearHammer / bullNail )
&& Transform( PCM, 2 ) <= bearHammer
) /*--------------------------------------------------------------------- Condition 1 */
|| ( shiftOneClose > shiftOneOpen
&& OoTMax >= ( bullHammer / ( shiftOneClose - shiftOneLow ) )
&& OoTMax >= ( bullHammer / bullNail )
&& Transform( PCM, 2 ) <= bullHammer
) /*---------------------------------------------------------------- .OR. Condition 2 */
)
&& ( ... ) /*---------------------------------------------------------------- .AND.Condition 3 */
&& ( ... ) /*---------------------------------------------------------------- .AND.Condition 4 */
&& ( ... ) /*---------------------------------------------------------------- .AND.Condition 5 */
&& ( ... ) /*---------------------------------------------------------------- .AND.Condition 6 */
&& ( ... ) /*---------------------------------------------------------------- .AND.Condition 7 */
&& ( ... ) /*---------------------------------------------------------------- .AND.Condition 8 */
&& ( ... ) /*---------------------------------------------------------------- .AND.Condition 9 */
&& ( ... ) /*---------------------------------------------------------------- .AND.Condition A */
&& ( ... ) /*---------------------------------------------------------------- .AND.Condition B */
)
{...} /*---------------------------------- CODE-BLOCK TO EXECUTE ------------------------------*/
In my ~ 20+ years of Quant modelling, we always preferred to have wide-layout (screens are cheap and having 4 x 2 and larger multi-screen seats is so easy and so common in more than a recent decade ), emphasis on the logic, then reducing dup-es in computation(s) (best pre-computing any & all logic-"control-values" to be then re-used and due to low-latency ( often ultra-low-latency ) reasons, we never resorted to spend any extra time on calling function ( overheads with context-switching & passing parameters there & results back ). Not all compilers (versions) did short-cutting the execution branches due to laws-of-logic, so care must be taken here ( most expensive functions being those that manipulate/query the db.POOL-storage with trades' data, having an awfully expensive costs of first having to do a db.POOL-pointer manipulation and then & only then (on success thereof & never otherwise) re-access the db.POOL-record's items of data ).
One should also notice that there is a logical blind-spot -- shiftOneClose == shiftOneOpen.

Related

What am i doing wrong in writing this Snowflake function with variables?

Another user was helping me with this problem, but i'm having trouble executing it, i'm getting error:
syntax error line 3 at position 8 unexpected 'time'. syntax error line 3 at position 23 unexpected ':'. (line 3)
it seems i'm either declaring the variables wrong, actually i'm sure of that because when i comment out "time", it gives me an error with "curDay".
Here is the function i'm trying to execute;
CREATE OR REPLACE FUNCTION DB_BI_DEV.RAW_CPMS_AAR.cfn_GetShiftIDFromDateTime (dateTime TIMESTAMP_NTZ(9), shiftCalendarID int)
RETURNS table (shiftID int)
AS
$$
DECLARE
time time TIME(:dateTime);
curDay int;
prvDay int;
shiftID int;
BEGIN
SELECT TOP 1
ID,
DATEDIFF( day, BeginDate, :dateTime ) % PeriodInDays + 1,
( :curDay + PeriodInDays - 2 ) % PeriodInDays + 1
INTO :shiftCalendarID, :curDay, :prvDay
FROM RAW_CPMS_AAR.ShiftCalendar
WHERE ID = :shiftCalendarID
OR ( :shiftCalendarID IS NULL
AND Name = 'Factory'
AND BeginDate <= :dateTime )
ORDER BY BeginDate DESC;
SELECT ID into :shiftID
FROM Shift
WHERE ShiftCalendarID = #shiftCalendarID
AND ( ( FromDay = :curDay AND FromTimeOfDay <= :time AND TillTimeOfDay > :time )
OR ( FromDay = :curDay AND FromTimeOfDay >= TillTimeOfDay AND FromTimeOfDay <= :time )
OR ( FromDay = :prvDay AND FromTimeOfDay >= TillTimeOfDay AND TillTimeOfDay > :time )
);
END;
$$
This may need some small changes, but should be close to what you require:
CREATE OR REPLACE FUNCTION DB_BI_DEV.RAW_CPMS_AAR.cfn_GetShiftIDFromDateTime (dateTime TIMESTAMP_NTZ(9), shiftCalendarID int)
RETURNS table (shiftID int)
AS
$$
WITH T0 (ShiftCalendarID, CurDay, PrvDay)
AS (
SELECT TOP 1
ID AS ShiftCalendarID,
DATEDIFF( day, BeginDate, :dateTime ) % PeriodInDays + 1 AS CurDay,
( CurDay + PeriodInDays - 2 ) % PeriodInDays + 1 AS PrvDay
FROM RAW_CPMS_AAR.ShiftCalendar
WHERE ID = :shiftCalendarID
OR ( :shiftCalendarID IS NULL
AND Name = 'Factory'
AND BeginDate <= :dateTime )
ORDER BY BeginDate DESC
),
T1 (TimeValue)
AS (
SELECT TIME_FROM_PARTS(
EXTRACT(HOUR FROM :datetime),
EXTRACT(MINUTE FROM :datetime),
EXTRACT(SECOND FROM :datetime))
)
)
SELECT ID as shiftID
FROM Shift, T0, T1
WHERE Shift.ShiftCalendarID = T0.ShiftCalendarID
AND ( ( FromDay = T0.CurDay AND FromTimeOfDay <= T1.TimeValue AND TillTimeOfDay > T1.TimeValue )
OR ( FromDay = T0.CurDay AND FromTimeOfDay >= TillTimeOfDay AND FromTimeOfDay <= T1.TimeValue )
OR ( FromDay = T0.PrvDay AND FromTimeOfDay >= TillTimeOfDay AND TillTimeOfDay > T1.TimeValue )
);
$$
To add on to Dave Weldon's solution - in UDF bodies, there are no colons in front of parameters. Instead of :shiftCalendarID it is shiftCalendarID and :dateTime is just dateTime. Colons are needed in Stored Procedures, because the parameters are treated as string literal constants, but this is not the case with User Defined Functions.

unexpected symbol near )

unexpected symbol near ')' on Line 10
I am new to programming and have followed everything in "LUA Tutorial 10b"
hook.Add( "PlayerSay", "CommandIdent", function( ply, text, team )
if( text == "!hurt" ) then
ply:SetHealth( ply:Health() - 25 )
if( ply:Health() <= 0 ) then
ply:Kill()
end
return "OUCH!"
end
if( string.sub( text, 1, 4, ) == "/ooc" ) then
return "[OOC]" .. string.sub( text, 5 )
end
end )
The script should translate "/ooc (message)" to "[OOC] (message)" when a user types it in game.
As stated by #char on the comments, apparently you've got an extra comma inline 10
if( string.sub( text, 1, 4, ) == "/ooc" ) then
It should be
if( string.sub( text, 1, 4 ) == "/ooc" ) then\
As stated in the lua wiki.

Email Notification when Expert Advisor fails to close a trading position

I'm trying to develop a piece of MQL4 code which sends you a notification when an position opened by an Expert Advisor fails to close/liquidate when the conditions specified by the Expert Advisor are met.
Here is what I have so far.The ClosePosition() returns true when the position is closed successfully and returns false when the EA fails to close the position. This is where the else if (ClosePosition == false) kicks in.
//Order Close//
string sym = Symbol();
int ordersTotal = OrdersTotal();
for(int PosSel = ordersTotal-1; PosSel>=0; PosSel--)
{
if(OrderSelect(PosSel,SELECT_BY_POS,MODE_TRADES))
if(OrderTicket() > 0)
if(OrderMagicNumber() == Period())
if(OrderSymbol() == Symbol())
if(TimeCurrent() >=(OrderOpenTime() + 60 * Period()))
{
ClosePosition = OrderClose(OrderTicket(),8,MarketInfo(sym,MODE_BID) + MarketInfo(sym,MODE_SPREAD) * MarketInfo(sym,MODE_POINT),300,clrNONE);
if(ClosePosition == true)
{
Sleep(60000);
int PosSelHist = OrdersHistoryTotal()-1;
bool reshist = OrderSelect(PosSelHist,SELECT_BY_POS,MODE_HISTORY);
if(reshist == true && Digits == 5)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail("Trade Notification Email (TNE)","Order# "+DoubleToStr(Ticket,0)+" has been closed on the account "+AccountName()+
"\n"+
"\nThe order exit price for this trade is "+DoubleToStr(ClosingPrice,5)+"with a profit/loss of"+DoubleToStr(Profit,2)+
"\n"+
"\nThe spread charge for this position is £"+DoubleToStr((spread*tickvalue)*LotSize,2)+
"\n"+
"\n-----------------------------------------------------------------------"+
"\n"+
SendNotification("Ticket # "+IntegerToString(Ticket,10)+"has closed with a profit/loss of "+DoubleToStr(Profit,2));
}
else if(reshist == true && Digits == 3)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail("Trade Notification Email (TNE)","Order# "+DoubleToStr(Ticket,0)+" has been placed on the account "+AccountName()+
"\n"+
"\nThe order entry price for this trade is "+DoubleToStr(ClosingPrice,3)+"with a profit/loss of"+DoubleToStr(Profit,2)+
"\n"+
"\nThe spread charge for this position is £"+DoubleToStr((spread*tickvalue)*LotSize,2)+
"\n"+
"\n-----------------------------------------------------------------------"+
SendNotification("Ticket # "+IntegerToString(Ticket,10)+" has closed with a profit/loss of "+DoubleToStr(Profit,2));
}
}
else if(ClosePosition == false)
{
int failedClosePosition = OrdersTotal()-1;
bool fail = OrderSelect(failedClosePosition,SELECT_BY_POS,MODE_HISTORY);
if(fail == true)
{
SendNotification("Order Number #"+IntegerToString(OrderTicket(),10)+" has failed to close. Please refer to error code "+IntegerToString(GetLastError()));
}
}
}
}
Firstly, is this the correct way in getting the desired result, and secondly; is this the correct way of coding the alternative for the ClosePosition == true, or would this be an if instead of an else if?
It is possible that you will try to close your position but fail due to some regular issues - requote, or trade context is busy or some other.
For such reason you MUST make sure the closing price is fresh
RefreshRates();
also you may try to solve TradeContext issue and others, alternative way - try to send some number of close requests:
int ATTEMPTS; // declare on a global scope
int OnInit(){ // initialise
ATTEMPTS = IsTesting() ? 1 : 100; // ternary-op =boolA?valB:valC
//---
return(INIT_SUCCEEDED);
}
void Order_Close(){
int ticket = GetTicketNumberToClose(); // put all checks here
TradeClose(ticket);
}
void TradeClose(int ticket){ // change to bool
// returning T/F if you need
while(IsTradeContextBusy()) Sleep(5); // a blocking-loop
int current_attempt = 0, err=-1;
while(current_attempt < ATTEMPTS){
RefreshRates(); // get fresh prices from Market
if (!OrderClose(ticket,OrderLots(),OrderClosePrice(),5)){
err = GetLastError();
current_attempt++;
}else return;
}
Print( __LINE__,
"failed to close ticket#", ticket,
" at price", DoubleToStr( OrderClosePrice(), Digits ),
". err#", err
); // send notification
// instead of Print() if you need
}
No, sorry. The code is hard to get confirmed to be correct.
Sure, a few syntax errors could be fixed.
A big portion of processing is duplicated, which may work, but is hard to maintain in a longer run and is considered a poor software engineering practice/habit.You may benefit from rather retaining a unique OrderTicket() value once searching the db.POOL and then straight SELECT_BY_TICKET, which is robust against all order_state / order_relative_position changes in both of the { MODE_TRADES | MODE_HISTORY } parts of the db.POOL.
Next is the worse enemy for the proposed MQL4 code:
If one may believe this, never block the flow of the code. MQL4 code-execution environment is event-based, triggered by the external source of events ( The Market ) and calling Sleep( 60000 ) is worse than taking a sleep on the rails, right in the exit from the EuroTunnel. OUCH!!
Your code is envictimed not to be able to react, and worse, not to be able to let other parts of the MQL4 code eco-system breathe in sync with the flow of The Market Events. There are sure better ways, how to do "almost nothing", than Sleep(), believe me.
Efficiency tips:
Avoid code-duplicates and rather use Digits-specific formatting, be it via a variable set to actual number of decimal places, or via StringFormat() patterns.
May enjoy a bit different layout of code, that will help you avoid syntax errors, missed parentheses et al.
Prefer to use globally unique, direct-pointer-alike OrderTicket() numbers, as evaluated in OrderClose() and rather pre-store it's value, as you wish to re-use it later in the code, but not having it readily available from the OrderClose()-moment.
May enjoy another IDE for MQL4 code-effort, where collapsing and columnar blocks become very handy ( Geany, SciTe, JEdit, Notepad++ ).Here, you soon physically view the inefficiency in if(){}else if(){} code-blocks, where the natural mutual {True|False}-dichotomy was duplicated in the else part.
Anyway, enjoy the wild worlds of MQL4
//Order Close//
string sym = Symbol();
int ordersTotal = OrdersTotal();
for ( int PosSel = ordersTotal - 1; // loopVar .SET
PosSel >= 0; // loopVar .PRE-condition
PosSel-- // loopVar .DEC at loop-end
)
{
if ( OrderSelect( PosSel, SELECT_BY_POS, MODE_TRADES ) )
if ( OrderTicket() > 0 )
if ( OrderMagicNumber() == Period() )
if ( OrderSymbol() == Symbol() )
if ( OrderOpenTime() <= TimeCurrent() - ( 60 * Period() ) )
{
ClosePosition = OrderClose( OrderTicket(),
8,
MarketInfo( sym, MODE_BID )
+ MarketInfo( sym, MODE_SPREAD )
* MarketInfo( sym, MODE_POINT ),
300,
clrNONE
);
if ( ClosePosition == true )
{ // ===================||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||====================
Sleep( 60000 ); //|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| BLOCKS EA-EXECUTION
// ===================||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||====================
int PosSelHist = OrdersHistoryTotal() - 1;
bool reshist = OrderSelect( PosSelHist, SELECT_BY_POS, MODE_HISTORY );
if ( reshist == true
&& Digits == 5
)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail( "Trade Notification Email (TNE)",
"Order# " + DoubleToStr( Ticket, 0 )
+ " has been closed on the account " + AccountName()
+ "\n"
+ "\nThe order exit price for this trade is " + DoubleToStr( ClosingPrice, 5 )
+ "with a profit/loss of" + DoubleToStr( Profit, 2 )
+ "\n"
+ "\nThe spread charge for this position is £" + DoubleToStr( ( spread
* tickvalue
)
* LotSize, 2 )
+ "\n"
+ "\n-----------------------------------------------------------------------"
+ "\n"
+ SendNotification( "Ticket # "
+ IntegerToString( Ticket, 10 )
+ "has closed with a profit/loss of "
+ DoubleToStr( Profit, 2 )
)
);
}
else if ( reshist == true
&& Digits == 3
)
{
double ClosingPrice = OrderClosePrice();
double OpeningPrice = OrderOpenPrice();
double Profit = OrderProfit();
int Ticket = OrderTicket();
SendMail( "Trade Notification Email (TNE)",
"Order# " + DoubleToStr( Ticket, 0 )
+ " has been placed on the account " + AccountName()
+ "\n"
+ "\nThe order entry price for this trade is " + DoubleToStr( ClosingPrice, 3 )
+ "with a profit/loss of" + DoubleToStr( Profit, 2 )
+ "\n"
+ "\nThe spread charge for this position is £" + DoubleToStr( ( spread
* tickvalue
)
* LotSize, 2 )
+ "\n"
+ "\n-----------------------------------------------------------------------"
+ SendNotification( "Ticket # "
+ IntegerToString( Ticket, 10 )
+ " has closed with a profit/loss of "
+ DoubleToStr( Profit, 2 )
)
);
}
}
else if ( ClosePosition == false )
{
int failedClosePosition = OrdersTotal() - 1;
bool fail = OrderSelect( failedClosePosition, SELECT_BY_POS, MODE_HISTORY );
if ( fail == true )
{
SendNotification( "Order Number #"
+ IntegerToString( OrderTicket(), 10 )
+ " has failed to close. Please refer to error code "
+ IntegerToString( GetLastError() )
);
}
}
}
}

Why is my EA not moving my position to breakeven?

I'm attempting to modify my market orders to breakeven the position when the position get 100 pips to the good. This also accounts for the StopLevels which are around 20-30 pips for my broker. It checks the param's via a "for(){...} loop" function
The MagicNumber is the timeframe number for the chart it is on (i.e. 240=4H, 60=1H) I don't set a TakeProfit price & initially no StopLoss price.
The EA is not adding a SL to be equal to the opening price when the trade reaches 100 pip in profit (plus stoplevels). Profit points reaches well over 130 points.
My code is below for a OP_SELL order - any help would be appreciated. Regards, Todd
/*Global Declarations*/
double pnlPoints;
double price, sl, tp;
double point;
int stopLevel;
int breakeven;
double newSL;
/*Local Declaratons*/
pnlPoints = 0;
point = MarketInfo( Symbol(), MODE_POINT );
stopLevel = int( MarketInfo( Symbol(), MODE_STOPLEVEL )
+ MarketInfo( Symbol(), MODE_SPREAD )
);
sl = NormalizeDouble( OrderStopLoss(), Digits );
tp = OrderTakeProfit();
breakeven = 100;
for( int s = OrdersTotal() - 1; s >= 0; s-- )
{ if ( ( OrderSelect( s, SELECT_BY_POS, MODE_TRADES ) ) == true )
price = MarketInfo( Symbol(), MODE_ASK );
newSL = NormalizeDouble( OrderOpenPrice(), Digits );
pnlPoints = ( OrderOpenPrice() - price ) / point;
if ( OP_SELL == OrderType() )
if ( Period() == OrderMagicNumber() )
if ( stopLevel < ( newSL - price ) / point )
if ( breakeven < pnlPoints )
if ( newSL != sl )
ModSell = OrderModify( OrderTicket(),
OrderOpenPrice(),
newSL,
tp,
buycolor
);
else if ( ModBuy == false )
{ Print( "OrderModify failed with error #",
GetLastError()
);
}
}
For the moment being,refine the codeandadd self-debuging / tracing code
After OrderModify() use a self-debugging / journaling Print( StringFormat( ... ) ) to document all instructed values used in the actual OrderModify() call and also the remote-execution ( { server-side | StrategyTester } ) reported issues.
The current code does not enter into such self-diagnostics and ModSell is not inspected at all, ModBuy is inspected only at uncertain conditions / by-coincidence at some future visit of the for(){...} code-execution path to a part after newSL == sl ( and all above stated conditions are just by chance met too )
Next, check an assigned value of tp
As stated above,
/*Local Declarations*/
...
tp = OrderTakeProfit();
which introduces a reasonable doubt, that re-using of this ( inherently uncertain value, as no one knows, which OrderSelect() was the last one that set a db.Pool pointer to decide, from which record from the db.Pool this veryOrderTakeProfit() would accidentally read ( if any record is present in db.Pool already ) inside the whole for(){...} traversing the db.Pool records will not meet conditions for setting properly a TakeProfit price in the next series of OrderModify() calls.
This seems to be the root cause, or a source of unhandled exceptions to the valid, Broker-compliant, OrderModify() values.
Try this:
if (newSL != sl ) {
ModSell = OrderModify( OrderTicket(),
OrderOpenPrice(),
OrderOpenPrice(),
0,
OrderExpiration(),
clrRed
);
if(ModBuy == false )
Print( "OrderModify failed with error #", GetLastError());
}
Then check the Expert-tab for error-message if it fails to set the stop.
Also, you need to take note that StopLoss will ONLY occur if you are on the right chart-timeframe; Otherwise, it won't even get into the if-statements.

How to verify that specific paths do not exist in cypher query

I would like to get nodes, which do no have a specific relation (a relation with specific properties).
The graph contains entity nodes (the n's), which occur at specific lines (line_nr) in files (the f).
The current query I have is as follows:
start n=node:entities("text:*")
MATCH p=(n)-[left:OCCURS]->(f)
, p4=(f)<-[right4?:OCCURS]-(n4)
, p7=(f)<-[right7?:OCCURS]-(n7)
WHERE ( (
( n4.text? =~ "nonreachablenodestextregex" AND (p4 = null OR left.line_nr < right4.line_nr - 0 OR left.line_nr > right4.line_nr + 0 OR ID(left) = ID(right4) ) ) )
AND (
( n7.text? =~ "othernonreachablenodestextregex" AND (p7 = null OR left.line_nr < right7.line_nr - 0 OR left.line_nr > right7.line_nr + 0 OR ID(left) = ID(right7) ) ) ) )
WITH n, left, f, count(*) as group_by_cause
RETURN ID(left) as occ_id,
n.text as ent_text,
substring(f.text, ABS(left.file_offset-1), 2 + LENGTH(n.text) ) as occ_text,
f.path as file_path,
left.line_nr as occ_line_nr,
ID(f) as file_id
Instead of a new path in the MATCH clause, I thought it would also be possible to have:
NOT ( (f)<-[right4:OCCURS]-(n4) )
But, I do not want to exclude the existence of any path, but specific paths.
As an alternative solution, I thought to include additional start nodes (as I have an index on the not to be reachable node), to remove the text comparison in the WHERE clause. This however doesn't return anything if there are no nodes in neo4j matching the wildcard.
start n=node:entities("text:*")
, n4=node:entities("text:nonreachablenodestextwildcard")
, n7=node:entities("text:othernonreachablenodestextwildcard")
MATCH p=(n)-[left:OCCURS]->(f)
, p4=(f)<-[right4?:OCCURS]-(n4)
, p7=(f)<-[right7?:OCCURS]-(n7)
WHERE ( (
( (p4 = null
OR left.line_nr < right4.line_nr - 0
OR left.line_nr > right4.line_nr + 0
OR ID(left) = ID(right4) ) ) )
AND (
( (p7 = null
OR left.line_nr < right7.line_nr - 0
OR left.line_nr > right7.line_nr + 0
OR ID(left) = ID(right7) ) )
) )
Old Update:
As mentioned in the answers, I could use the predicate functions to construct an inner query. I therefore updated the query to:
start n=node:entities("text:*")
MATCH p=(n)-[left:OCCURS]->(f)
WHERE ( (
(NONE(path in (f)<-[:OCCURS]-(n4)
WHERE
(LAST(nodes(path))).text =~ "nonreachablenodestextRegex"
AND FIRST(r4 in rels(p)).line_nr <= left.line_nr
AND FIRST(r4 in rels(p)).line_nr >= left.line_nr
)
) )
AND (
(NONE(path in (f)<-[:OCCURS]-(n7)
WHERE
(LAST(nodes(path))).text =~ "othernonreachablenodestextRegex"
AND FIRST(r7 in rels(p)).line_nr <= left.line_nr
AND FIRST(r7 in rels(p)).line_nr >= left.line_nr
)
) )
)
WITH n, left, f, count(*) as group_by_cause
RETURN ....
This gives me an java.lang.OutOfMemoryException :
java.lang.OutOfMemoryError: Java heap space
at java.util.regex.Pattern.compile(Pattern.java:1432)
at java.util.regex.Pattern.<init>(Pattern.java:1133)
at java.util.regex.Pattern.compile(Pattern.java:823)
at scala.util.matching.Regex.<init>(Regex.scala:38)
at scala.collection.immutable.StringLike$class.r(StringLike.scala:226)
at scala.collection.immutable.StringOps.r(StringOps.scala:31)
at org.neo4j.cypher.internal.parser.v1_9.Base.ignoreCase(Base.scala:31)
at org.neo4j.cypher.internal.parser.v1_9.Base.ignoreCases(Base.scala:49)
at org.neo4j.cypher.internal.parser.v1_9.Base$$anonfun$ignoreCases$1.apply(Base.scala:49)
at org.neo4j.cypher.internal.parser.v1_9.Base$$anonfun$ignoreCases$1.apply(Base.scala:49)
at scala.util.parsing.combinator.Parsers$Parser.p$3(Parsers.scala:209)
at scala.util.parsing.combinator.Parsers$Parser$$anonfun$append$1$$anonfun$apply$1.apply(Parsers.scala:210)
at scala.util.parsing.combinator.Parsers$Parser$$anonfun$append$1$$anonfun$apply$1.apply(Parsers.scala:210)
at scala.util.parsing.combinator.Parsers$Failure.append(Parsers.scala:163)
at scala.util.parsing.combinator.Parsers$Parser$$anonfun$append$1.apply(Parsers.scala:210)
at scala.util.parsing.combinator.Parsers$Parser$$anonfun$append$1.apply(Parsers.scala:210)
at scala.util.parsing.combinator.Parsers$$anon$3.apply(Parsers.scala:183)
at scala.util.parsing.combinator.Parsers$Parser$$anonfun$append$1$$anonfun$apply$1.apply(Parsers.scala:210)
at scala.util.parsing.combinator.Parsers$Parser$$anonfun$append$1$$anonfun$apply$1.apply(Parsers.scala:210)
at scala.util.parsing.combinator.Parsers$Failure.append(Parsers.scala:163)
(The last 6 lines are repeated a few more times)
Solution
The previous update probably contains a syntax error somewhere, got it fixed slightly different as follows:
start n=node:entities("text:*")
MATCH p=(n)-[left:OCCURS]->(f)
WHERE (
(NONE ( path in (f)<-[:OCCURS]-()
WHERE
ANY(n4 in nodes(path)
WHERE ID(n4) <> ID(n)
AND n4.type = 'ENTITY'
AND n4.text =~ "a regex expr"
)
AND ALL(r4 in rels(path)
WHERE r4.line_nr <= left.line_nr + 0
AND r4.line_nr >= left.line_nr - 0
)
)
) )
AND
NONE ( ...... )
WITH n, left, f, count(*) as group_by_cause
RETURN ...
It is however slow. Order of seconds (>10) for small graph:
4 entities-nodes and 6 :OCCURS relations in total, all to 1 single destination f node, with line_nr's between 0 and 3.
Performance Update
The following is about twice as fast:
start n=node:entities("text:*")
MATCH p=(n)-[left:OCCURS]->(f)
, p4=(f)<-[right4?:OCCURS]-(n4)
, p7=(f)<-[right7?:OCCURS]-(n7)
WHERE
( n4.text? =~ "regex1"
AND (p4 = null
OR left.line_nr < right4.line_nr - 0
OR left.line_nr > right4.line_nr + 0
OR ID(left) = ID(right4)
)
)
AND
( n7.text? =~ "regex2"
AND (p7 = null .....)
)
WITH n, left, f, count(*) as group_by_cause
RETURN ....
I think instead of the optional relationships you should use the pattern predicates in WHERE as you noted. The pattern expressions actually return a collection of paths, so you could do collection predicates like (ALL, NONE, ANY, SINGLE)
WHERE NONE(path in (f)<-[:OCCURS]-(n4) WHERE
ALL(r in rels(p) : r.line_nr = 42 ))
see: http://docs.neo4j.org/chunked/milestone/query-function.html#_predicates

Resources